diff --git a/.gitignore b/.gitignore index 19660052..5bc8cd8d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,8 @@ **/kernel8.img node_modules +.bundle .vendor Gemfile.lock -package-lock.json +package*.json diff --git a/03_hacky_hello_world/README.md b/03_hacky_hello_world/README.md index d868459f..71293c56 100644 --- a/03_hacky_hello_world/README.md +++ b/03_hacky_hello_world/README.md @@ -188,13 +188,15 @@ diff -uNr 02_runtime_init/src/bsp/raspberrypi.rs 03_hacky_hello_world/src/bsp/ra diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs --- 02_runtime_init/src/console.rs +++ 03_hacky_hello_world/src/console.rs -@@ -0,0 +1,19 @@ +@@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! System console. + ++use crate::bsp; ++ +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- @@ -208,6 +210,17 @@ diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs + /// intention. + pub use core::fmt::Write; +} ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++/// Return a reference to the console. ++/// ++/// This is the global console used by all printing macros. ++pub fn console() -> impl interface::Write { ++ bsp::console::console() ++} diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs --- 02_runtime_init/src/main.rs @@ -317,7 +330,7 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs + +//! Printing. + -+use crate::{bsp, console}; ++use crate::console; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- @@ -328,7 +341,7 @@ diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs +pub fn _print(args: fmt::Arguments) { + use console::interface::Write; + -+ bsp::console::console().write_fmt(args).unwrap(); ++ console::console().write_fmt(args).unwrap(); +} + +/// Prints without a newline. diff --git a/03_hacky_hello_world/src/console.rs b/03_hacky_hello_world/src/console.rs index 5ab4cc45..7d940f29 100644 --- a/03_hacky_hello_world/src/console.rs +++ b/03_hacky_hello_world/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -17,3 +19,14 @@ pub mod interface { /// intention. pub use core::fmt::Write; } + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> impl interface::Write { + bsp::console::console() +} diff --git a/03_hacky_hello_world/src/print.rs b/03_hacky_hello_world/src/print.rs index 81c6d179..05ef2aea 100644 --- a/03_hacky_hello_world/src/print.rs +++ b/03_hacky_hello_world/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -15,7 +15,7 @@ use core::fmt; pub fn _print(args: fmt::Arguments) { use console::interface::Write; - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/04_safe_globals/README.md b/04_safe_globals/README.md index 18827b5c..58c14dc2 100644 --- a/04_safe_globals/README.md +++ b/04_safe_globals/README.md @@ -148,7 +148,7 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr } Ok(()) -@@ -41,7 +80,37 @@ +@@ -41,7 +80,39 @@ // Public Code //-------------------------------------------------------------------------------------------------- @@ -164,9 +164,9 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr /// Return a reference to the console. -pub fn console() -> impl console::interface::Write { - QEMUOutput {} -+pub fn console() -> &'static impl console::interface::All { ++pub fn console() -> &'static dyn console::interface::All { + &QEMU_OUTPUT -+} + } + +//------------------------------------------------------------------------------ +// OS Interface Code @@ -187,12 +187,14 @@ diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/console.rs 04_safe_globals/sr + fn chars_written(&self) -> usize { + self.inner.lock(|inner| inner.chars_written) + } - } ++} ++ ++impl console::interface::All for QEMUOutput {} diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs --- 03_hacky_hello_world/src/console.rs +++ 04_safe_globals/src/console.rs -@@ -10,10 +10,22 @@ +@@ -12,12 +12,24 @@ /// Console interfaces. pub mod interface { @@ -218,7 +220,17 @@ diff -uNr 03_hacky_hello_world/src/console.rs 04_safe_globals/src/console.rs + } + + /// Trait alias for a full-fledged console. -+ pub trait All = Write + Statistics; ++ pub trait All: Write + Statistics {} + } + + //-------------------------------------------------------------------------------------------------- +@@ -27,6 +39,6 @@ + /// Return a reference to the console. + /// + /// This is the global console used by all printing macros. +-pub fn console() -> impl interface::Write { ++pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs @@ -240,25 +252,35 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_safe_globals/src/main.rs /// Early init code. /// -@@ -124,7 +126,15 @@ +@@ -124,7 +126,12 @@ /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { - println!("Hello from Rust!"); -+ use console::interface::Statistics; ++ use console::console; - panic!("Stopping here.") + println!("[0] Hello from Rust!"); + -+ println!( -+ "[1] Chars written: {}", -+ bsp::console::console().chars_written() -+ ); ++ println!("[1] Chars written: {}", console().chars_written()); + + println!("[2] Stopping here."); + cpu::wait_forever() } +diff -uNr 03_hacky_hello_world/src/print.rs 04_safe_globals/src/print.rs +--- 03_hacky_hello_world/src/print.rs ++++ 04_safe_globals/src/print.rs +@@ -13,8 +13,6 @@ + + #[doc(hidden)] + pub fn _print(args: fmt::Arguments) { +- use console::interface::Write; +- + console::console().write_fmt(args).unwrap(); + } + + diff -uNr 03_hacky_hello_world/src/synchronization.rs 04_safe_globals/src/synchronization.rs --- 03_hacky_hello_world/src/synchronization.rs +++ 04_safe_globals/src/synchronization.rs diff --git a/04_safe_globals/src/bsp/raspberrypi/console.rs b/04_safe_globals/src/bsp/raspberrypi/console.rs index 774dbadb..6427e099 100644 --- a/04_safe_globals/src/bsp/raspberrypi/console.rs +++ b/04_safe_globals/src/bsp/raspberrypi/console.rs @@ -90,7 +90,7 @@ impl QEMUOutput { } /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { +pub fn console() -> &'static dyn console::interface::All { &QEMU_OUTPUT } @@ -114,3 +114,5 @@ impl console::interface::Statistics for QEMUOutput { self.inner.lock(|inner| inner.chars_written) } } + +impl console::interface::All for QEMUOutput {} diff --git a/04_safe_globals/src/console.rs b/04_safe_globals/src/console.rs index 3894c18d..94e00f84 100644 --- a/04_safe_globals/src/console.rs +++ b/04_safe_globals/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -27,5 +29,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Statistics; + pub trait All: Write + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/04_safe_globals/src/main.rs b/04_safe_globals/src/main.rs index 15db4a21..4726477d 100644 --- a/04_safe_globals/src/main.rs +++ b/04_safe_globals/src/main.rs @@ -126,14 +126,11 @@ mod synchronization; /// /// - Only a single core must be active and running this function. unsafe fn kernel_init() -> ! { - use console::interface::Statistics; + use console::console; println!("[0] Hello from Rust!"); - println!( - "[1] Chars written: {}", - bsp::console::console().chars_written() - ); + println!("[1] Chars written: {}", console().chars_written()); println!("[2] Stopping here."); cpu::wait_forever() diff --git a/04_safe_globals/src/print.rs b/04_safe_globals/src/print.rs index 81c6d179..f69bad44 100644 --- a/04_safe_globals/src/print.rs +++ b/04_safe_globals/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/05_drivers_gpio_uart/README.md b/05_drivers_gpio_uart/README.md index 6f0057d6..555ac031 100644 --- a/05_drivers_gpio_uart/README.md +++ b/05_drivers_gpio_uart/README.md @@ -27,12 +27,6 @@ - `BSP`s now contain a memory map in `src/bsp/raspberrypi/memory.rs`. In the specific case, they contain the Raspberry's `MMIO` addresses which are used to instantiate the respective device drivers. -- We also modify the `panic!` handler, so that it does not anymore rely on `println!`, which uses - the globally-shared instance of the `UART` that might be locked when an error is encountered (for - now, this can't happen due to the `NullLock`, but with a real lock it becomes an issue). - - Instead, it creates a new UART driver instance, re-initializes the device and uses that one to - print. This increases the chances that the system is able to print a final important message - before it suspends itself. ## Boot it from SD card @@ -98,8 +92,8 @@ Miniterm 1.0 [0] mingo version 0.5.0 [1] Booting on: Raspberry Pi 3 [2] Drivers loaded: - 1. BCM GPIO - 2. BCM PL011 UART + 1. BCM PL011 UART + 2. BCM GPIO [3] Chars written: 117 [4] Echoing input now ``` @@ -234,7 +228,7 @@ diff -uNr 04_safe_globals/src/_arch/aarch64/cpu.rs 05_drivers_gpio_uart/src/_arc diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -0,0 +1,225 @@ +@@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -345,16 +339,13 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g +/// Abstraction for the associated MMIO registers. +type Registers = MMIODerefWrapper; + -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+pub struct GPIOInner { ++struct GPIOInner { + registers: Registers, +} + -+// Export the inner struct so that BSPs can use it for the panic handler. -+pub use GPIOInner as PanicGPIO; ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- + +/// Representation of the GPIO HW. +pub struct GPIO { @@ -362,7 +353,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g +} + +//-------------------------------------------------------------------------------------------------- -+// Public Code ++// Private Code +//-------------------------------------------------------------------------------------------------- + +impl GPIOInner { @@ -385,7 +376,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g + // Make an educated guess for a good delay value (Sequence described in the BCM2837 + // peripherals PDF). + // -+ // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz. ++ // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. + // - The Linux 2837 GPIO driver waits 1 µs between the steps. + // + // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs @@ -432,7 +423,13 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g + } +} + ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ +impl GPIO { ++ pub const COMPATIBLE: &'static str = "BCM GPIO"; ++ + /// Create an instance. + /// + /// # Safety @@ -457,14 +454,14 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 05_drivers_g + +impl driver::interface::DeviceDriver for GPIO { + fn compatible(&self) -> &'static str { -+ "BCM GPIO" ++ Self::COMPATIBLE + } +} diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -0,0 +1,402 @@ +@@ -0,0 +1,407 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter @@ -634,18 +631,15 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + NonBlocking, +} + -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+pub struct PL011UartInner { ++struct PL011UartInner { + registers: Registers, + chars_written: usize, + chars_read: usize, +} + -+// Export the inner struct so that BSPs can use it for the panic handler. -+pub use PL011UartInner as PanicUart; ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- + +/// Representation of the UART. +pub struct PL011Uart { @@ -653,7 +647,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri +} + +//-------------------------------------------------------------------------------------------------- -+// Public Code ++// Private Code +//-------------------------------------------------------------------------------------------------- + +impl PL011UartInner { @@ -793,7 +787,13 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + } +} + ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ +impl PL011Uart { ++ pub const COMPATIBLE: &'static str = "BCM PL011 UART"; ++ + /// Create an instance. + /// + /// # Safety @@ -813,7 +813,7 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + +impl driver::interface::DeviceDriver for PL011Uart { + fn compatible(&self) -> &'static str { -+ "BCM PL011 UART" ++ Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { @@ -867,6 +867,8 @@ diff -uNr 04_safe_globals/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 05_dri + self.inner.lock(|inner| inner.chars_read) + } +} ++ ++impl console::interface::All for PL011Uart {} diff -uNr 04_safe_globals/src/bsp/device_driver/bcm.rs 05_drivers_gpio_uart/src/bsp/device_driver/bcm.rs --- 04_safe_globals/src/bsp/device_driver/bcm.rs @@ -947,24 +949,19 @@ diff -uNr 04_safe_globals/src/bsp/device_driver.rs 05_drivers_gpio_uart/src/bsp/ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs --- 04_safe_globals/src/bsp/raspberrypi/console.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs -@@ -4,113 +4,34 @@ +@@ -4,115 +4,13 @@ //! BSP console facilities. -use crate::{console, synchronization, synchronization::NullLock}; -+use super::memory; -+use crate::{bsp::device_driver, console}; - use core::fmt; - - //-------------------------------------------------------------------------------------------------- +-use core::fmt; +- +-//-------------------------------------------------------------------------------------------------- -// Private Definitions -+// Public Code - //-------------------------------------------------------------------------------------------------- - +-//-------------------------------------------------------------------------------------------------- +- -/// A mystical, magical device for generating QEMU output out of the void. -+/// In case of a panic, the panic handler uses this function to take a last shot at printing -+/// something before the system is halted. - /// +-/// -/// The mutex protected part. -struct QEMUOutputInner { - chars_written: usize, @@ -1007,13 +1004,9 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr -/// 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. -+/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -+/// with synchronization primitives, which increases chances that we get to print something, even -+/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. - /// +-/// -/// The function takes an `&mut self`, so it must be implemented for the inner struct. -+/// # Safety - /// +-/// -/// See [`src/print.rs`]. -/// -/// [`src/print.rs`]: ../../print/index.html @@ -1031,11 +1024,12 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr - Ok(()) - } -} -- --//-------------------------------------------------------------------------------------------------- --// Public Code --//-------------------------------------------------------------------------------------------------- -- ++use crate::console; + + //-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- + -impl QEMUOutput { - /// Create a new instance. - pub const fn new() -> QEMUOutput { @@ -1043,18 +1037,10 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr - inner: NullLock::new(QEMUOutputInner::new()), - } - } -+/// - Use only for printing during a panic. -+pub unsafe fn panic_console_out() -> impl fmt::Write { -+ let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); -+ let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); -+ -+ panic_gpio.map_pl011_uart(); -+ panic_uart.init(); -+ panic_uart - } - +-} +- /// Return a reference to the console. - pub fn console() -> &'static impl console::interface::All { + pub fn console() -> &'static dyn console::interface::All { - &QEMU_OUTPUT -} - @@ -1077,20 +1063,23 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/console.rs 05_drivers_gpio_uart/sr - fn chars_written(&self) -> usize { - self.inner.lock(|inner| inner.chars_written) - } -+ &super::PL011_UART ++ &super::driver::PL011_UART } +- +-impl console::interface::All for QEMUOutput {} diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs --- 04_safe_globals/src/bsp/raspberrypi/driver.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs -@@ -0,0 +1,49 @@ +@@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2018-2022 Andre Richter + +//! BSP driver support. + -+use crate::driver; ++use super::memory::map::mmio; ++use crate::{bsp::device_driver, driver}; + +//-------------------------------------------------------------------------------------------------- +// Private Definitions @@ -1105,8 +1094,13 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src +// Global instances +//-------------------------------------------------------------------------------------------------- + ++pub(super) static PL011_UART: device_driver::PL011Uart = ++ unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; ++ ++static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; ++ +static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -+ device_drivers: [&super::GPIO, &super::PL011_UART], ++ device_drivers: [&PL011_UART, &GPIO], +}; + +//-------------------------------------------------------------------------------------------------- @@ -1130,7 +1124,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/driver.rs 05_drivers_gpio_uart/src + + fn post_device_driver_init(&self) { + // Configure PL011Uart's output pins. -+ super::GPIO.map_pl011_uart(); ++ GPIO.map_pl011_uart(); + } +} @@ -1179,7 +1173,7 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi/memory.rs 05_drivers_gpio_uart/src diff -uNr 04_safe_globals/src/bsp/raspberrypi.rs 05_drivers_gpio_uart/src/bsp/raspberrypi.rs --- 04_safe_globals/src/bsp/raspberrypi.rs +++ 05_drivers_gpio_uart/src/bsp/raspberrypi.rs -@@ -6,3 +6,33 @@ +@@ -6,3 +6,22 @@ pub mod console; pub mod cpu; @@ -1187,17 +1181,6 @@ diff -uNr 04_safe_globals/src/bsp/raspberrypi.rs 05_drivers_gpio_uart/src/bsp/ra +pub mod memory; + +//-------------------------------------------------------------------------------------------------- -+// Global instances -+//-------------------------------------------------------------------------------------------------- -+use super::device_driver; -+ -+static GPIO: device_driver::GPIO = -+ unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; -+ -+static PL011_UART: device_driver::PL011Uart = -+ unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; -+ -+//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + @@ -1230,7 +1213,7 @@ diff -uNr 04_safe_globals/src/bsp.rs 05_drivers_gpio_uart/src/bsp.rs diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs --- 04_safe_globals/src/console.rs +++ 05_drivers_gpio_uart/src/console.rs -@@ -14,8 +14,25 @@ +@@ -16,8 +16,25 @@ /// Console write functions. pub trait Write { @@ -1256,7 +1239,7 @@ diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs } /// Console statistics. -@@ -24,8 +41,13 @@ +@@ -26,10 +43,15 @@ fn chars_written(&self) -> usize { 0 } @@ -1268,10 +1251,12 @@ diff -uNr 04_safe_globals/src/console.rs 05_drivers_gpio_uart/src/console.rs } /// Trait alias for a full-fledged console. -- pub trait All = Write + Statistics; -+ pub trait All = Write + Read + Statistics; +- pub trait All: Write + Statistics {} ++ pub trait All: Write + Read + Statistics {} } + //-------------------------------------------------------------------------------------------------- + diff -uNr 04_safe_globals/src/cpu.rs 05_drivers_gpio_uart/src/cpu.rs --- 04_safe_globals/src/cpu.rs +++ 05_drivers_gpio_uart/src/cpu.rs @@ -1353,16 +1338,15 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -125,16 +127,54 @@ +@@ -125,13 +127,50 @@ /// # Safety /// /// - Only a single core must be active and running this function. +/// - The init calls in this function must appear in the correct order. unsafe fn kernel_init() -> ! { -- use console::interface::Statistics; +- use console::console; + use driver::interface::DriverManager; - -- println!("[0] Hello from Rust!"); ++ + for i in bsp::driver::driver_manager().all_device_drivers().iter() { + if let Err(x) = i.init() { + panic!("Error loading driver: {}: {}", i.compatible(), x); @@ -1370,17 +1354,20 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs + } + bsp::driver::driver_manager().post_device_driver_init(); + // println! is usable from here on. -+ + +- println!("[0] Hello from Rust!"); + // Transition from unsafe to safe. + kernel_main() +} -+ + +- println!("[1] Chars written: {}", console().chars_written()); +/// The main function running after the early init. +fn kernel_main() -> ! { -+ use bsp::console::console; -+ use console::interface::All; ++ use console::console; + use driver::interface::DriverManager; -+ + +- println!("[2] Stopping here."); +- cpu::wait_forever() + println!( + "[0] {} version {}", + env!("CARGO_PKG_NAME"), @@ -1396,69 +1383,18 @@ diff -uNr 04_safe_globals/src/main.rs 05_drivers_gpio_uart/src/main.rs + { + println!(" {}. {}", i + 1, driver.compatible()); + } - - println!( -- "[1] Chars written: {}", -+ "[3] Chars written: {}", - bsp::console::console().chars_written() - ); ++ ++ println!("[3] Chars written: {}", console().chars_written()); + println!("[4] Echoing input now"); - -- println!("[2] Stopping here."); -- cpu::wait_forever() ++ + // Discard any spurious received characters before going into echo mode. + console().clear_rx(); + loop { -+ let c = bsp::console::console().read_char(); -+ bsp::console::console().write_char(c); ++ let c = console().read_char(); ++ console().write_char(c); + } } -diff -uNr 04_safe_globals/src/panic_wait.rs 05_drivers_gpio_uart/src/panic_wait.rs ---- 04_safe_globals/src/panic_wait.rs -+++ 05_drivers_gpio_uart/src/panic_wait.rs -@@ -4,13 +4,29 @@ - - //! A panic handler that infinitely waits. - --use crate::{cpu, println}; --use core::panic::PanicInfo; -+use crate::{bsp, cpu}; -+use core::{fmt, panic::PanicInfo}; - - //-------------------------------------------------------------------------------------------------- - // Private Code - //-------------------------------------------------------------------------------------------------- - -+fn _panic_print(args: fmt::Arguments) { -+ use fmt::Write; -+ -+ unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -+} -+ -+/// Prints with a newline - only use from the panic handler. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! panic_println { -+ ($($arg:tt)*) => ({ -+ _panic_print(format_args_nl!($($arg)*)); -+ }) -+} -+ - /// Stop immediately if called a second time. - /// - /// # Note -@@ -50,7 +66,7 @@ - _ => ("???", 0, 0), - }; - -- println!( -+ panic_println!( - "Kernel panic!\n\n\ - Panic location:\n File '{}', line {}, column {}\n\n\ - {}", - diff -uNr 04_safe_globals/tests/boot_test_string.rb 05_drivers_gpio_uart/tests/boot_test_string.rb --- 04_safe_globals/tests/boot_test_string.rb +++ 05_drivers_gpio_uart/tests/boot_test_string.rb diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 76ce3bd1..0601d58e 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -148,7 +145,7 @@ impl GPIOInner { // Make an educated guess for a good delay value (Sequence described in the BCM2837 // peripherals PDF). // - // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz. + // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. // - The Linux 2837 GPIO driver waits 1 µs between the steps. // // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs @@ -195,7 +192,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -220,6 +223,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs +++ b/05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/05_drivers_gpio_uart/src/console.rs b/05_drivers_gpio_uart/src/console.rs index e49e241f..c1fb0e53 100644 --- a/05_drivers_gpio_uart/src/console.rs +++ b/05_drivers_gpio_uart/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/05_drivers_gpio_uart/src/main.rs b/05_drivers_gpio_uart/src/main.rs index 2e8bfeaa..c9b73382 100644 --- a/05_drivers_gpio_uart/src/main.rs +++ b/05_drivers_gpio_uart/src/main.rs @@ -145,8 +145,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use driver::interface::DriverManager; println!( @@ -165,16 +164,13 @@ fn kernel_main() -> ! { println!(" {}. {}", i + 1, driver.compatible()); } - println!( - "[3] Chars written: {}", - bsp::console::console().chars_written() - ); + println!("[3] Chars written: {}", console().chars_written()); println!("[4] Echoing input now"); // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/05_drivers_gpio_uart/src/panic_wait.rs b/05_drivers_gpio_uart/src/panic_wait.rs index e546b06d..fb30e8d4 100644 --- a/05_drivers_gpio_uart/src/panic_wait.rs +++ b/05_drivers_gpio_uart/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -66,7 +50,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/05_drivers_gpio_uart/src/print.rs b/05_drivers_gpio_uart/src/print.rs index 81c6d179..f69bad44 100644 --- a/05_drivers_gpio_uart/src/print.rs +++ b/05_drivers_gpio_uart/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/06_uart_chainloader/README.md b/06_uart_chainloader/README.md index 20c120d4..38f9cc05 100644 --- a/06_uart_chainloader/README.md +++ b/06_uart_chainloader/README.md @@ -66,6 +66,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -74,14 +75,14 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 6 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 +[MP] ⏩ Pushing 7 KiB ==========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now [0] mingo version 0.5.0 [1] Booting on: Raspberry Pi 3 [2] Drivers loaded: - 1. BCM GPIO - 2. BCM PL011 UART + 1. BCM PL011 UART + 2. BCM GPIO [3] Chars written: 117 [4] Echoing input now ``` @@ -324,23 +325,10 @@ diff -uNr 05_drivers_gpio_uart/src/_arch/aarch64/cpu/boot.s 06_uart_chainloader/ // Infinitely wait for events (aka "park the core"). .L_parking_loop: -diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs ---- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -+++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -148,7 +148,7 @@ - // Make an educated guess for a good delay value (Sequence described in the BCM2837 - // peripherals PDF). - // -- // - According to Wikipedia, the fastest Pi3 clocks around 1.4 GHz. -+ // - According to Wikipedia, the fastest RPi4 clocks around 1.5 GHz. - // - The Linux 2837 GPIO driver waits 1 µs between the steps. - // - // So lets try to be on the safe side and default to 2000 cycles, which would equal 1 µs - diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -278,7 +278,7 @@ +@@ -275,7 +275,7 @@ } /// Retrieve a character. @@ -349,7 +337,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 // If RX FIFO is empty, if self.registers.FR.matches_all(FR::RXFE::SET) { // immediately return in non-blocking mode. -@@ -293,12 +293,7 @@ +@@ -290,12 +290,7 @@ } // Read one character. @@ -363,7 +351,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0 // Update statistics. self.chars_read += 1; -@@ -378,14 +373,14 @@ +@@ -381,14 +376,14 @@ impl console::interface::Read for PL011Uart { fn read_char(&self) -> char { self.inner @@ -426,19 +414,14 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/kernel.ld 06_uart_chainloader diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader/src/bsp/raspberrypi/memory.rs --- 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs +++ 06_uart_chainloader/src/bsp/raspberrypi/memory.rs -@@ -11,9 +11,10 @@ +@@ -11,6 +11,7 @@ /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { + pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; -- pub const GPIO_OFFSET: usize = 0x0020_0000; -- pub const UART_OFFSET: usize = 0x0020_1000; -+ pub const GPIO_OFFSET: usize = 0x0020_0000; -+ pub const UART_OFFSET: usize = 0x0020_1000; - - /// Physical devices. - #[cfg(feature = "bsp_rpi3")] + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; @@ -35,3 +36,13 @@ pub const PL011_UART_START: usize = START + UART_OFFSET; } @@ -457,7 +440,7 @@ diff -uNr 05_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 06_uart_chainloader diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs --- 05_drivers_gpio_uart/src/main.rs +++ 06_uart_chainloader/src/main.rs -@@ -143,38 +143,56 @@ +@@ -143,34 +143,55 @@ kernel_main() } @@ -470,8 +453,7 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs + /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; - use driver::interface::DriverManager; - println!( @@ -502,10 +484,7 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs + console().write_char(3 as char); } -- println!( -- "[3] Chars written: {}", -- bsp::console::console().chars_written() -- ); +- println!("[3] Chars written: {}", console().chars_written()); - println!("[4] Echoing input now"); + // Read the binary's size. + let mut size: u32 = u32::from(console().read_char() as u8); @@ -516,8 +495,8 @@ diff -uNr 05_drivers_gpio_uart/src/main.rs 06_uart_chainloader/src/main.rs - // Discard any spurious received characters before going into echo mode. - console().clear_rx(); - loop { -- let c = bsp::console::console().read_char(); -- bsp::console::console().write_char(c); +- let c = console().read_char(); +- console().write_char(c); + // Trust it's not too big. + console().write_char('O'); + console().write_char('K'); diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index 5c68107a..0601d58e 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -195,7 +192,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -220,6 +223,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 7d66484b..df56d7c4 100644 --- a/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -321,7 +318,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -341,7 +344,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -395,3 +398,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/06_uart_chainloader/src/bsp/raspberrypi.rs b/06_uart_chainloader/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/06_uart_chainloader/src/bsp/raspberrypi/console.rs b/06_uart_chainloader/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/console.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/driver.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/06_uart_chainloader/src/bsp/raspberrypi/memory.rs b/06_uart_chainloader/src/bsp/raspberrypi/memory.rs index 0959bdce..6ef46c35 100644 --- a/06_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ b/06_uart_chainloader/src/bsp/raspberrypi/memory.rs @@ -13,8 +13,8 @@ pub(super) mod map { pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; - pub const GPIO_OFFSET: usize = 0x0020_0000; - pub const UART_OFFSET: usize = 0x0020_1000; + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; /// Physical devices. #[cfg(feature = "bsp_rpi3")] diff --git a/06_uart_chainloader/src/console.rs b/06_uart_chainloader/src/console.rs index e49e241f..c1fb0e53 100644 --- a/06_uart_chainloader/src/console.rs +++ b/06_uart_chainloader/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/06_uart_chainloader/src/main.rs b/06_uart_chainloader/src/main.rs index b8e6fea4..08bd9ad9 100644 --- a/06_uart_chainloader/src/main.rs +++ b/06_uart_chainloader/src/main.rs @@ -152,8 +152,7 @@ const MINILOAD_LOGO: &str = r#" /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; println!("{}", MINILOAD_LOGO); println!("{:^37}", bsp::board_name()); diff --git a/06_uart_chainloader/src/panic_wait.rs b/06_uart_chainloader/src/panic_wait.rs index e546b06d..fb30e8d4 100644 --- a/06_uart_chainloader/src/panic_wait.rs +++ b/06_uart_chainloader/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -66,7 +50,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/06_uart_chainloader/src/print.rs b/06_uart_chainloader/src/print.rs index 81c6d179..f69bad44 100644 --- a/06_uart_chainloader/src/print.rs +++ b/06_uart_chainloader/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/07_timestamps/README.md b/07_timestamps/README.md index 6b8dcbeb..2f4ab323 100644 --- a/07_timestamps/README.md +++ b/07_timestamps/README.md @@ -19,6 +19,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -30,16 +31,16 @@ Minipush 1.0 [MP] ⏩ Pushing 12 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.140431] mingo version 0.7.0 -[ 0.140630] Booting on: Raspberry Pi 3 -[ 0.141085] Architectural timer resolution: 52 ns -[ 0.141660] Drivers loaded: -[ 0.141995] 1. BCM GPIO -[ 0.142353] 2. BCM PL011 UART -[W 0.142777] Spin duration smaller than architecturally supported, skipping -[ 0.143621] Spinning for 1 second -[ 1.144023] Spinning for 1 second -[ 2.144245] Spinning for 1 second +[ 0.143123] mingo version 0.7.0 +[ 0.143323] Booting on: Raspberry Pi 3 +[ 0.143778] Architectural timer resolution: 52 ns +[ 0.144352] Drivers loaded: +[ 0.144688] 1. BCM PL011 UART +[ 0.145110] 2. BCM GPIO +[W 0.145469] Spin duration smaller than architecturally supported, skipping +[ 0.146313] Spinning for 1 second +[ 1.146715] Spinning for 1 second +[ 2.146938] Spinning for 1 second ``` ## Diff to previous @@ -374,7 +375,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -143,25 +143,19 @@ +@@ -140,25 +140,19 @@ /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -410,7 +411,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_times diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -278,7 +278,7 @@ +@@ -275,7 +275,7 @@ } /// Retrieve a character. @@ -419,7 +420,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07 // If RX FIFO is empty, if self.registers.FR.matches_all(FR::RXFE::SET) { // immediately return in non-blocking mode. -@@ -293,7 +293,12 @@ +@@ -290,7 +290,12 @@ } // Read one character. @@ -433,7 +434,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07 // Update statistics. self.chars_read += 1; -@@ -373,14 +378,14 @@ +@@ -376,14 +381,14 @@ impl console::interface::Read for PL011Uart { fn read_char(&self) -> char { self.inner @@ -496,19 +497,14 @@ diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/kernel.ld 07_timestamps/src/bs diff -uNr 06_uart_chainloader/src/bsp/raspberrypi/memory.rs 07_timestamps/src/bsp/raspberrypi/memory.rs --- 06_uart_chainloader/src/bsp/raspberrypi/memory.rs +++ 07_timestamps/src/bsp/raspberrypi/memory.rs -@@ -11,10 +11,9 @@ +@@ -11,7 +11,6 @@ /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { - pub const BOARD_DEFAULT_LOAD_ADDRESS: usize = 0x8_0000; -- pub const GPIO_OFFSET: usize = 0x0020_0000; -- pub const UART_OFFSET: usize = 0x0020_1000; -+ pub const GPIO_OFFSET: usize = 0x0020_0000; -+ pub const UART_OFFSET: usize = 0x0020_1000; - - /// Physical devices. - #[cfg(feature = "bsp_rpi3")] + pub const GPIO_OFFSET: usize = 0x0020_0000; + pub const UART_OFFSET: usize = 0x0020_1000; @@ -36,13 +35,3 @@ pub const PL011_UART_START: usize = START + UART_OFFSET; } @@ -546,7 +542,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs /// Early init code. /// -@@ -143,56 +144,38 @@ +@@ -143,55 +144,38 @@ kernel_main() } @@ -559,8 +555,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs - /// The main function running after the early init. fn kernel_main() -> ! { -- use bsp::console::console; -- use console::interface::All; +- use console::console; + use core::time::Duration; + use driver::interface::DriverManager; + use time::interface::TimeManager; @@ -635,7 +630,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs --- 06_uart_chainloader/src/panic_wait.rs +++ 07_timestamps/src/panic_wait.rs -@@ -58,18 +58,23 @@ +@@ -42,18 +42,23 @@ #[panic_handler] fn panic(info: &PanicInfo) -> ! { @@ -650,7 +645,7 @@ diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs _ => ("???", 0, 0), }; - panic_println!( + println!( - "Kernel panic!\n\n\ + "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ @@ -664,7 +659,7 @@ diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs --- 06_uart_chainloader/src/print.rs +++ 07_timestamps/src/print.rs -@@ -36,3 +36,59 @@ +@@ -34,3 +34,59 @@ $crate::print::_print(format_args_nl!($($arg)*)); }) } diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/07_timestamps/src/bsp/raspberrypi.rs b/07_timestamps/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/07_timestamps/src/bsp/raspberrypi.rs +++ b/07_timestamps/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/07_timestamps/src/bsp/raspberrypi/console.rs b/07_timestamps/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/07_timestamps/src/bsp/raspberrypi/console.rs +++ b/07_timestamps/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/07_timestamps/src/bsp/raspberrypi/driver.rs b/07_timestamps/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/07_timestamps/src/bsp/raspberrypi/driver.rs +++ b/07_timestamps/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/07_timestamps/src/console.rs b/07_timestamps/src/console.rs index e49e241f..c1fb0e53 100644 --- a/07_timestamps/src/console.rs +++ b/07_timestamps/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/07_timestamps/src/panic_wait.rs b/07_timestamps/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/07_timestamps/src/panic_wait.rs +++ b/07_timestamps/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/07_timestamps/src/print.rs b/07_timestamps/src/print.rs index 9ec13a28..8705eec0 100644 --- a/07_timestamps/src/print.rs +++ b/07_timestamps/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/08_hw_debug_JTAG/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs +++ b/08_hw_debug_JTAG/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/08_hw_debug_JTAG/src/console.rs b/08_hw_debug_JTAG/src/console.rs index e49e241f..c1fb0e53 100644 --- a/08_hw_debug_JTAG/src/console.rs +++ b/08_hw_debug_JTAG/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/08_hw_debug_JTAG/src/panic_wait.rs b/08_hw_debug_JTAG/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/08_hw_debug_JTAG/src/panic_wait.rs +++ b/08_hw_debug_JTAG/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/08_hw_debug_JTAG/src/print.rs b/08_hw_debug_JTAG/src/print.rs index 9ec13a28..8705eec0 100644 --- a/08_hw_debug_JTAG/src/print.rs +++ b/08_hw_debug_JTAG/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/09_privilege_level/README.md b/09_privilege_level/README.md index 2320dfd7..63cbcb89 100644 --- a/09_privilege_level/README.md +++ b/09_privilege_level/README.md @@ -166,6 +166,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -177,20 +178,20 @@ Minipush 1.0 [MP] ⏩ Pushing 14 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.165757] mingo version 0.9.0 -[ 0.165957] Booting on: Raspberry Pi 3 -[ 0.166412] Current privilege level: EL1 -[ 0.166888] Exception handling state: -[ 0.167333] Debug: Masked -[ 0.167723] SError: Masked -[ 0.168112] IRQ: Masked -[ 0.168502] FIQ: Masked -[ 0.168893] Architectural timer resolution: 52 ns -[ 0.169467] Drivers loaded: -[ 0.169803] 1. BCM GPIO -[ 0.170160] 2. BCM PL011 UART -[ 0.170583] Timer test, spinning for 1 second -[ 1.171115] Echoing input now +[ 0.162546] mingo version 0.9.0 +[ 0.162745] Booting on: Raspberry Pi 3 +[ 0.163201] Current privilege level: EL1 +[ 0.163677] Exception handling state: +[ 0.164122] Debug: Masked +[ 0.164511] SError: Masked +[ 0.164901] IRQ: Masked +[ 0.165291] FIQ: Masked +[ 0.165681] Architectural timer resolution: 52 ns +[ 0.166255] Drivers loaded: +[ 0.166592] 1. BCM PL011 UART +[ 0.167014] 2. BCM GPIO +[ 0.167371] Timer test, spinning for 1 second +[ 1.167904] Echoing input now ``` ## Diff to previous @@ -505,16 +506,15 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs mod panic_wait; mod print; mod synchronization; -@@ -146,6 +147,8 @@ +@@ -146,6 +147,7 @@ /// The main function running after the early init. fn kernel_main() -> ! { -+ use bsp::console::console; -+ use console::interface::All; ++ use console::console; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; -@@ -157,6 +160,12 @@ +@@ -157,6 +159,12 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -527,7 +527,7 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs info!( "Architectural timer resolution: {} ns", time::time_manager().resolution().as_nanos() -@@ -171,11 +180,15 @@ +@@ -171,11 +179,15 @@ info!(" {}. {}", i + 1, driver.compatible()); } @@ -543,8 +543,8 @@ diff -uNr 08_hw_debug_JTAG/src/main.rs 09_privilege_level/src/main.rs loop { - info!("Spinning for 1 second"); - time::time_manager().spin_for(Duration::from_secs(1)); -+ let c = bsp::console::console().read_char(); -+ bsp::console::console().write_char(c); ++ let c = console().read_char(); ++ console().write_char(c); } } diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/09_privilege_level/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/09_privilege_level/src/bsp/raspberrypi.rs b/09_privilege_level/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/09_privilege_level/src/bsp/raspberrypi.rs +++ b/09_privilege_level/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/09_privilege_level/src/bsp/raspberrypi/console.rs b/09_privilege_level/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/09_privilege_level/src/bsp/raspberrypi/console.rs +++ b/09_privilege_level/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/09_privilege_level/src/bsp/raspberrypi/driver.rs b/09_privilege_level/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/09_privilege_level/src/bsp/raspberrypi/driver.rs +++ b/09_privilege_level/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/09_privilege_level/src/console.rs b/09_privilege_level/src/console.rs index e49e241f..c1fb0e53 100644 --- a/09_privilege_level/src/console.rs +++ b/09_privilege_level/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/09_privilege_level/src/main.rs b/09_privilege_level/src/main.rs index 0c6a0dec..6c1ab310 100644 --- a/09_privilege_level/src/main.rs +++ b/09_privilege_level/src/main.rs @@ -147,8 +147,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; @@ -188,7 +187,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/09_privilege_level/src/panic_wait.rs b/09_privilege_level/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/09_privilege_level/src/panic_wait.rs +++ b/09_privilege_level/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/09_privilege_level/src/print.rs b/09_privilege_level/src/print.rs index 9ec13a28..8705eec0 100644 --- a/09_privilege_level/src/print.rs +++ b/09_privilege_level/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/10_virtual_mem_part1_identity_mapping/README.md b/10_virtual_mem_part1_identity_mapping/README.md index 802243c8..04b82eca 100644 --- a/10_virtual_mem_part1_identity_mapping/README.md +++ b/10_virtual_mem_part1_identity_mapping/README.md @@ -314,6 +314,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -325,25 +326,25 @@ Minipush 1.0 [MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 1.034062] mingo version 0.10.0 -[ 1.034270] Booting on: Raspberry Pi 3 -[ 1.034725] MMU online. Special regions: -[ 1.035201] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 1.036220] 0x1fff0000 - 0x1fffffff | 64 KiB | Dev RW PXN | Remapped Device MMIO -[ 1.037205] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO -[ 1.038094] Current privilege level: EL1 -[ 1.038570] Exception handling state: -[ 1.039015] Debug: Masked -[ 1.039405] SError: Masked -[ 1.039794] IRQ: Masked -[ 1.040184] FIQ: Masked -[ 1.040575] Architectural timer resolution: 52 ns -[ 1.041148] Drivers loaded: -[ 1.041484] 1. BCM GPIO -[ 1.041842] 2. BCM PL011 UART -[ 1.042264] Timer test, spinning for 1 second +[ 0.811167] mingo version 0.10.0 +[ 0.811374] Booting on: Raspberry Pi 3 +[ 0.811829] MMU online. Special regions: +[ 0.812306] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.813324] 0x1fff0000 - 0x1fffffff | 64 KiB | Dev RW PXN | Remapped Device MMIO +[ 0.814310] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.815198] Current privilege level: EL1 +[ 0.815675] Exception handling state: +[ 0.816119] Debug: Masked +[ 0.816509] SError: Masked +[ 0.816899] IRQ: Masked +[ 0.817289] FIQ: Masked +[ 0.817679] Architectural timer resolution: 52 ns +[ 0.818253] Drivers loaded: +[ 0.818589] 1. BCM PL011 UART +[ 0.819011] 2. BCM GPIO +[ 0.819369] Timer test, spinning for 1 second [ !!! ] Writing through the remapped UART at 0x1FFF_1000 -[ 2.043305] Echoing input now +[ 1.820409] Echoing input now ``` ## Diff to previous @@ -1118,7 +1119,16 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { -@@ -160,6 +171,9 @@ +@@ -147,7 +158,7 @@ + + /// The main function running after the early init. + fn kernel_main() -> ! { +- use console::console; ++ use console::{console, interface::Write}; + use core::time::Duration; + use driver::interface::DriverManager; + use time::interface::TimeManager; +@@ -159,6 +170,9 @@ ); info!("Booting on: {}", bsp::board_name()); @@ -1128,7 +1138,7 @@ diff -uNr 09_privilege_level/src/main.rs 10_virtual_mem_part1_identity_mapping/s let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); -@@ -183,6 +197,13 @@ +@@ -182,6 +196,13 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs +++ b/10_virtual_mem_part1_identity_mapping/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/10_virtual_mem_part1_identity_mapping/src/console.rs b/10_virtual_mem_part1_identity_mapping/src/console.rs index e49e241f..c1fb0e53 100644 --- a/10_virtual_mem_part1_identity_mapping/src/console.rs +++ b/10_virtual_mem_part1_identity_mapping/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/10_virtual_mem_part1_identity_mapping/src/main.rs b/10_virtual_mem_part1_identity_mapping/src/main.rs index dde224e7..6f92c676 100644 --- a/10_virtual_mem_part1_identity_mapping/src/main.rs +++ b/10_virtual_mem_part1_identity_mapping/src/main.rs @@ -158,8 +158,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::{console, interface::Write}; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; @@ -209,7 +208,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs +++ b/10_virtual_mem_part1_identity_mapping/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/10_virtual_mem_part1_identity_mapping/src/print.rs b/10_virtual_mem_part1_identity_mapping/src/print.rs index 9ec13a28..8705eec0 100644 --- a/10_virtual_mem_part1_identity_mapping/src/print.rs +++ b/10_virtual_mem_part1_identity_mapping/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index 81e633be..355ea297 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -417,31 +417,31 @@ Minipush 1.0 [MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.787414] mingo version 0.11.0 -[ 0.787621] Booting on: Raspberry Pi 3 -[ 0.788076] MMU online. Special regions: -[ 0.788553] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 0.789571] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO -[ 0.790460] Current privilege level: EL1 -[ 0.790936] Exception handling state: -[ 0.791380] Debug: Masked -[ 0.791770] SError: Masked -[ 0.792160] IRQ: Masked -[ 0.792550] FIQ: Masked -[ 0.792940] Architectural timer resolution: 52 ns -[ 0.793514] Drivers loaded: -[ 0.793850] 1. BCM GPIO -[ 0.794208] 2. BCM PL011 UART -[ 0.794630] Timer test, spinning for 1 second -[ 1.795161] -[ 1.795165] Trying to read from address 8 GiB... -[ 1.795715] ************************************************ -[ 1.796407] Whoa! We recovered from a synchronous exception! -[ 1.797100] ************************************************ -[ 1.797794] -[ 1.797967] Let's try again -[ 1.798303] Trying to read from address 9 GiB... -[ 1.798867] Kernel panic! +[ 0.798323] mingo version 0.11.0 +[ 0.798530] Booting on: Raspberry Pi 3 +[ 0.798985] MMU online. Special regions: +[ 0.799462] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.800480] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.801369] Current privilege level: EL1 +[ 0.801845] Exception handling state: +[ 0.802290] Debug: Masked +[ 0.802680] SError: Masked +[ 0.803069] IRQ: Masked +[ 0.803459] FIQ: Masked +[ 0.803849] Architectural timer resolution: 52 ns +[ 0.804423] Drivers loaded: +[ 0.804759] 1. BCM PL011 UART +[ 0.805182] 2. BCM GPIO +[ 0.805539] Timer test, spinning for 1 second +[ 1.806070] +[ 1.806074] Trying to read from address 8 GiB... +[ 1.806624] ************************************************ +[ 1.807316] Whoa! We recovered from a synchronous exception! +[ 1.808009] ************************************************ +[ 1.808703] +[ 1.808876] Let's try again +[ 1.809212] Trying to read from address 9 GiB... +[ 1.809776] Kernel panic! Panic location: File 'src/_arch/aarch64/exception.rs', line 58, column 5 @@ -464,25 +464,25 @@ SPSR_EL1: 0x600003c5 IRQ (I): Masked FIQ (F): Masked Illegal Execution State (IL): Not set -ELR_EL1: 0x0000000000082194 +ELR_EL1: 0x00000000000845f8 General purpose register: - x0 : 0x0000000000000000 x1 : 0x0000000000085517 - x2 : 0x0000000000000027 x3 : 0x0000000000084380 - x4 : 0x0000000000000006 x5 : 0xfb5f341800000000 - x6 : 0x0000000000000000 x7 : 0x7f91bc012b2b0209 - x8 : 0x0000000240000000 x9 : 0x0000000000085517 + x0 : 0x0000000000000000 x1 : 0x0000000000086187 + x2 : 0x0000000000000027 x3 : 0x0000000000081280 + x4 : 0x0000000000000006 x5 : 0x1e27329c00000000 + x6 : 0x0000000000000000 x7 : 0xd3d18908028f0243 + x8 : 0x0000000240000000 x9 : 0x0000000000086187 x10: 0x0000000000000443 x11: 0x000000003f201000 x12: 0x0000000000000019 x13: 0x00000000ffffd8f0 x14: 0x000000000000147b x15: 0x00000000ffffff9c x16: 0x000000000007fd38 x17: 0x0000000005f5e0ff - x18: 0x0000000000000030 x19: 0x0000000000090008 - x20: 0x0000000000085350 x21: 0x000000003b9aca00 - x22: 0x0000000000082e4c x23: 0x0000000000082308 + x18: 0x00000000000c58fc x19: 0x0000000000090008 + x20: 0x0000000000085fc0 x21: 0x000000003b9aca00 + x22: 0x0000000000082238 x23: 0x00000000000813d4 x24: 0x0000000010624dd3 x25: 0xffffffffc4653600 - x26: 0x0000000000086638 x27: 0x0000000000085410 - x28: 0x0000000000084f90 x29: 0x0000000000086538 - lr : 0x0000000000082188 + x26: 0x0000000000086988 x27: 0x0000000000086080 + x28: 0x0000000000085f10 x29: 0x0000000000085c00 + lr : 0x00000000000845ec ``` ## Diff to previous @@ -1033,7 +1033,16 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/main.rs 11_exceptions_part1_ if let Err(string) = memory::mmu::mmu().enable_mmu_and_caching() { panic!("MMU: {}", string); } -@@ -197,13 +199,28 @@ +@@ -158,7 +160,7 @@ + + /// The main function running after the early init. + fn kernel_main() -> ! { +- use console::{console, interface::Write}; ++ use console::console; + use core::time::Duration; + use driver::interface::DriverManager; + use time::interface::TimeManager; +@@ -196,13 +198,28 @@ info!("Timer test, spinning for 1 second"); time::time_manager().spin_for(Duration::from_secs(1)); diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/11_exceptions_part1_groundwork/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs +++ b/11_exceptions_part1_groundwork/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/11_exceptions_part1_groundwork/src/console.rs b/11_exceptions_part1_groundwork/src/console.rs index e49e241f..c1fb0e53 100644 --- a/11_exceptions_part1_groundwork/src/console.rs +++ b/11_exceptions_part1_groundwork/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/11_exceptions_part1_groundwork/src/main.rs b/11_exceptions_part1_groundwork/src/main.rs index 96743601..12386153 100644 --- a/11_exceptions_part1_groundwork/src/main.rs +++ b/11_exceptions_part1_groundwork/src/main.rs @@ -160,8 +160,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use core::time::Duration; use driver::interface::DriverManager; use time::interface::TimeManager; @@ -226,7 +225,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/11_exceptions_part1_groundwork/src/panic_wait.rs b/11_exceptions_part1_groundwork/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/11_exceptions_part1_groundwork/src/panic_wait.rs +++ b/11_exceptions_part1_groundwork/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/11_exceptions_part1_groundwork/src/print.rs b/11_exceptions_part1_groundwork/src/print.rs index 9ec13a28..8705eec0 100644 --- a/11_exceptions_part1_groundwork/src/print.rs +++ b/11_exceptions_part1_groundwork/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index 14dc3878..e0d0dd1d 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -266,8 +266,10 @@ implementation in `lib.rs`: #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); @@ -275,12 +277,12 @@ unsafe fn kernel_init() -> ! { } ``` -Note the call to `bsp::console::qemu_bring_up_console()`. Since we are running all our tests inside -`QEMU`, we need to ensure that whatever peripheral implements the kernel's `console` interface is -initialized, so that we can print from our tests. If you recall [tutorial 03], bringing up -peripherals in `QEMU` might not need the full initialization as is needed on real hardware (setting -clocks, config registers, etc...) due to the abstractions in `QEMU`'s emulation code. So this is an -opportunity to cut down on setup code. +Note the call to `bsp::driver::driver_manager().qemu_bring_up_console()`. Since we are running all +our tests inside `QEMU`, we need to ensure that whatever peripheral implements the kernel's +`console` interface is initialized, so that we can print from our tests. If you recall [tutorial +03], bringing up peripherals in `QEMU` might not need the full initialization as is needed on real +hardware (setting clocks, config registers, etc...) due to the abstractions in `QEMU`'s emulation +code. So this is an opportunity to cut down on setup code. [tutorial 03]: ../03_hacky_hello_world @@ -620,13 +622,15 @@ your test code into individual chunks. For example, take a look at `tests/01_tim #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. @@ -714,14 +718,15 @@ so the wanted outcome is a `panic!`. Here is the whole test (minus some inline c mod panic_exit_success; -use libkernel::{bsp, cpu, exception, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -788,15 +793,15 @@ The subtest first sends `"ABC"` over the console to the kernel, and then expects /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs index 22edb4fa..a9a7261a 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi.rs @@ -9,17 +9,6 @@ pub mod cpu; pub mod driver; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs index eaef0b1f..0a630eef 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/console.rs @@ -4,45 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -/// -/// For the RPi, nothing needs to be done. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() {} diff --git a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs index b5538baa..f8acd335 100644 --- a/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ b/12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,9 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } + + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) {} } diff --git a/12_integrated_testing/kernel/src/console.rs b/12_integrated_testing/kernel/src/console.rs index e49e241f..c1fb0e53 100644 --- a/12_integrated_testing/kernel/src/console.rs +++ b/12_integrated_testing/kernel/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/12_integrated_testing/kernel/src/driver.rs b/12_integrated_testing/kernel/src/driver.rs index 2fcc7562..12d60ad4 100644 --- a/12_integrated_testing/kernel/src/driver.rs +++ b/12_integrated_testing/kernel/src/driver.rs @@ -40,5 +40,10 @@ pub mod interface { /// /// For example, device driver code that depends on other drivers already being online. fn post_device_driver_init(&self); + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/12_integrated_testing/kernel/src/lib.rs b/12_integrated_testing/kernel/src/lib.rs index 2de7d6cc..eef112f0 100644 --- a/12_integrated_testing/kernel/src/lib.rs +++ b/12_integrated_testing/kernel/src/lib.rs @@ -177,8 +177,10 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/12_integrated_testing/kernel/src/main.rs b/12_integrated_testing/kernel/src/main.rs index 11b6547d..bf4d7fe3 100644 --- a/12_integrated_testing/kernel/src/main.rs +++ b/12_integrated_testing/kernel/src/main.rs @@ -49,8 +49,7 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { - use bsp::console::console; - use console::interface::All; + use console::console; use driver::interface::DriverManager; info!("{}", libkernel::version()); @@ -84,7 +83,7 @@ fn kernel_main() -> ! { // Discard any spurious received characters before going into echo mode. console().clear_rx(); loop { - let c = bsp::console::console().read_char(); - bsp::console::console().write_char(c); + let c = console().read_char(); + console().write_char(c); } } diff --git a/12_integrated_testing/kernel/src/panic_wait.rs b/12_integrated_testing/kernel/src/panic_wait.rs index 6f09f11c..8bedfded 100644 --- a/12_integrated_testing/kernel/src/panic_wait.rs +++ b/12_integrated_testing/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -86,7 +70,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/12_integrated_testing/kernel/src/print.rs b/12_integrated_testing/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/12_integrated_testing/kernel/src/print.rs +++ b/12_integrated_testing/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/12_integrated_testing/kernel/tests/00_console_sanity.rs b/12_integrated_testing/kernel/tests/00_console_sanity.rs index dccb6cc2..e12a711f 100644 --- a/12_integrated_testing/kernel/tests/00_console_sanity.rs +++ b/12_integrated_testing/kernel/tests/00_console_sanity.rs @@ -11,15 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/12_integrated_testing/kernel/tests/01_timer_sanity.rs b/12_integrated_testing/kernel/tests/01_timer_sanity.rs index 59ef4a7f..390cdee5 100644 --- a/12_integrated_testing/kernel/tests/01_timer_sanity.rs +++ b/12_integrated_testing/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,15 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs index 9be94acd..62908377 100644 --- a/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs +++ b/12_integrated_testing/kernel/tests/02_exception_sync_page_fault.rs @@ -17,14 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs index f25ed645..3f4eae79 100644 --- a/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs +++ b/12_integrated_testing/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,10 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index d6c6a7e4..bc468be8 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -29,7 +29,6 @@ + [The GICv2 Driver (Pi 4)](#the-gicv2-driver-pi-4) - [GICC Details](#gicc-details) - [GICD Details](#gicd-details) -- [UART hack](#uart-hack) - [Test it](#test-it) - [Diff to previous](#diff-to-previous) @@ -282,7 +281,7 @@ fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -667,6 +666,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -678,26 +678,26 @@ Minipush 1.0 [MP] ⏩ Pushing 66 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 1.010579] mingo version 0.13.0 -[ 1.010787] Booting on: Raspberry Pi 3 -[ 1.011242] MMU online. Special regions: -[ 1.011718] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 1.012737] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO -[ 1.013625] Current privilege level: EL1 -[ 1.014102] Exception handling state: -[ 1.014546] Debug: Masked -[ 1.014936] SError: Masked -[ 1.015326] IRQ: Unmasked -[ 1.015738] FIQ: Masked -[ 1.016127] Architectural timer resolution: 52 ns -[ 1.016702] Drivers loaded: -[ 1.017038] 1. BCM GPIO -[ 1.017395] 2. BCM PL011 UART -[ 1.017817] 3. BCM Interrupt Controller -[ 1.018348] Registered IRQ handlers: -[ 1.018782] Peripheral handler: -[ 1.019228] 57. BCM PL011 UART -[ 1.019735] Echoing input now +[ 0.822492] mingo version 0.13.0 +[ 0.822700] Booting on: Raspberry Pi 3 +[ 0.823155] MMU online. Special regions: +[ 0.823632] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.824650] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO +[ 0.825539] Current privilege level: EL1 +[ 0.826015] Exception handling state: +[ 0.826459] Debug: Masked +[ 0.826849] SError: Masked +[ 0.827239] IRQ: Unmasked +[ 0.827651] FIQ: Masked +[ 0.828041] Architectural timer resolution: 52 ns +[ 0.828615] Drivers loaded: +[ 0.828951] 1. BCM PL011 UART +[ 0.829373] 2. BCM GPIO +[ 0.829731] 3. BCM Interrupt Controller +[ 0.830262] Registered IRQ handlers: +[ 0.830695] Peripheral handler: +[ 0.831141] 57. BCM PL011 UART +[ 0.831649] Echoing input now ``` Raspberry Pi 4: @@ -710,6 +710,7 @@ Minipush 1.0 [MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ✅ Serial connected [MP] 🔌 Please power the target now + __ __ _ _ _ _ | \/ (_)_ _ (_) | ___ __ _ __| | | |\/| | | ' \| | |__/ _ \/ _` / _` | @@ -721,26 +722,26 @@ Minipush 1.0 [MP] ⏩ Pushing 73 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 1.030536] mingo version 0.13.0 -[ 1.030569] Booting on: Raspberry Pi 4 -[ 1.031024] MMU online. Special regions: -[ 1.031501] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data -[ 1.032519] 0xfe000000 - 0xff84ffff | 24 MiB | Dev RW PXN | Device MMIO -[ 1.033408] Current privilege level: EL1 -[ 1.033884] Exception handling state: -[ 1.034328] Debug: Masked -[ 1.034718] SError: Masked -[ 1.035108] IRQ: Unmasked -[ 1.035520] FIQ: Masked -[ 1.035910] Architectural timer resolution: 18 ns -[ 1.036484] Drivers loaded: -[ 1.036820] 1. BCM GPIO -[ 1.037178] 2. BCM PL011 UART -[ 1.037600] 3. GICv2 (ARM Generic Interrupt Controller v2) -[ 1.038337] Registered IRQ handlers: -[ 1.038770] Peripheral handler: -[ 1.039217] 153. BCM PL011 UART -[ 1.039725] Echoing input now +[ 0.886853] mingo version 0.13.0 +[ 0.886886] Booting on: Raspberry Pi 4 +[ 0.887341] MMU online. Special regions: +[ 0.887818] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data +[ 0.888836] 0xfe000000 - 0xff84ffff | 24 MiB | Dev RW PXN | Device MMIO +[ 0.889725] Current privilege level: EL1 +[ 0.890201] Exception handling state: +[ 0.890645] Debug: Masked +[ 0.891035] SError: Masked +[ 0.891425] IRQ: Unmasked +[ 0.891837] FIQ: Masked +[ 0.892227] Architectural timer resolution: 18 ns +[ 0.892801] Drivers loaded: +[ 0.893137] 1. BCM PL011 UART +[ 0.893560] 2. BCM GPIO +[ 0.893917] 3. GICv2 (ARM Generic Interrupt Controller v2) +[ 0.894654] Registered IRQ handlers: +[ 0.895087] Peripheral handler: +[ 0.895534] 153. BCM PL011 UART +[ 0.896042] Echoing input now ``` ## Diff to previous @@ -896,21 +897,19 @@ diff -uNr 12_integrated_testing/kernel/src/_arch/aarch64/exception.rs 13_excepti //! //! crate::exception::arch_exception -+use crate::{bsp, exception}; ++use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ -@@ -102,8 +103,11 @@ +@@ -102,8 +103,9 @@ } #[no_mangle] -unsafe extern "C" fn current_elx_irq(e: &mut ExceptionContext) { - default_exception_handler(e); +unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { -+ use exception::asynchronous::interface::IRQManager; -+ + let token = &exception::asynchronous::IRQContext::new(); -+ bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); ++ exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] @@ -1268,7 +1267,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1 diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -0,0 +1,219 @@ +@@ -0,0 +1,221 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1385,6 +1384,8 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. + const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + ++ pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; ++ + /// Create an instance. + /// + /// # Safety @@ -1406,7 +1407,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc + +impl driver::interface::DeviceDriver for GICv2 { + fn compatible(&self) -> &'static str { -+ "GICv2 (ARM Generic Interrupt Controller v2)" ++ Self::COMPATIBLE + } + + unsafe fn init(&self) -> Result<(), &'static str> { @@ -1515,7 +1516,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs }; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, -@@ -121,7 +121,7 @@ +@@ -118,7 +118,7 @@ /// Representation of the GPIO HW. pub struct GPIO { @@ -1524,7 +1525,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs } //-------------------------------------------------------------------------------------------------- -@@ -197,7 +197,7 @@ +@@ -200,7 +200,7 @@ /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new(mmio_start_addr: usize) -> Self { Self { @@ -1709,7 +1710,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -0,0 +1,131 @@ +@@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -1740,6 +1741,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + +/// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. +#[derive(Copy, Clone)] ++#[allow(missing_docs)] +pub enum IRQNumber { + Local(LocalIRQ), + Peripheral(PeripheralIRQ), @@ -1786,12 +1788,14 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + ++ pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; ++ + /// Create an instance. + /// + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. -+ pub const unsafe fn new(_local_mmio_start_addr: usize, periph_mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { + Self { + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + } @@ -1804,7 +1808,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru + +impl driver::interface::DeviceDriver for InterruptController { + fn compatible(&self) -> &'static str { -+ "BCM Interrupt Controller" ++ Self::COMPATIBLE + } +} + @@ -1921,7 +1925,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u (0x44 => ICR: WriteOnly), (0x48 => @END), } -@@ -182,7 +231,8 @@ +@@ -179,7 +228,8 @@ /// Representation of the UART. pub struct PL011Uart { @@ -1931,7 +1935,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u } //-------------------------------------------------------------------------------------------------- -@@ -250,6 +300,14 @@ +@@ -247,6 +297,14 @@ .LCR_H .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled); @@ -1946,7 +1950,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u // Turn the UART on. self.registers .CR -@@ -332,9 +390,13 @@ +@@ -335,9 +393,13 @@ /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. @@ -1962,17 +1966,16 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u } } } -@@ -354,6 +416,21 @@ +@@ -357,6 +419,20 @@ Ok(()) } + + fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { -+ use bsp::exception::asynchronous::irq_manager; -+ use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; ++ use exception::asynchronous::{irq_manager, IRQDescriptor}; + + let descriptor = IRQDescriptor { -+ name: "BCM PL011 UART", ++ name: Self::COMPATIBLE, + handler: self, + }; + @@ -1984,10 +1987,10 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_u } impl console::interface::Write for PL011Uart { -@@ -400,3 +477,24 @@ - self.inner.lock(|inner| inner.chars_read) - } +@@ -405,3 +481,24 @@ } + + impl console::interface::All for PL011Uart {} + +impl exception::asynchronous::interface::IRQHandler for PL011Uart { + fn handle(&self) -> Result<(), &'static str> { @@ -2047,7 +2050,19 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver.rs 13_exceptions_pa diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs -@@ -12,7 +12,7 @@ +@@ -4,29 +4,43 @@ + + //! BSP driver support. + +-use super::memory::map::mmio; ++use super::{exception, memory::map::mmio}; + use crate::{bsp::device_driver, driver}; + ++pub use device_driver::IRQNumber; ++ + //-------------------------------------------------------------------------------------------------- + // Private Definitions + //-------------------------------------------------------------------------------------------------- /// Device Driver Manager type. struct BSPDriverManager { @@ -2056,16 +2071,31 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/driver.rs 13_exceptio } //-------------------------------------------------------------------------------------------------- -@@ -20,7 +20,11 @@ + // Global instances //-------------------------------------------------------------------------------------------------- +-pub(super) static PL011_UART: device_driver::PL011Uart = +- unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; ++pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { ++ device_driver::PL011Uart::new( ++ mmio::PL011_UART_START, ++ exception::asynchronous::irq_map::PL011_UART, ++ ) ++}; + + static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + ++#[cfg(feature = "bsp_rpi3")] ++pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = ++ unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; ++ ++#[cfg(feature = "bsp_rpi4")] ++pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = ++ unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; ++ static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { -- device_drivers: [&super::GPIO, &super::PL011_UART], -+ device_drivers: [ -+ &super::GPIO, -+ &super::PL011_UART, -+ &super::INTERRUPT_CONTROLLER, -+ ], +- device_drivers: [&PL011_UART, &GPIO], ++ device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], }; //-------------------------------------------------------------------------------------------------- @@ -2080,7 +2110,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronou + +//! BSP asynchronous exception handling. + -+use crate::{bsp, exception}; ++use crate::{bsp, bsp::driver, exception}; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions @@ -2108,7 +2138,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception/asynchronou +pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< + IRQNumberType = bsp::device_driver::IRQNumber, +> { -+ &super::super::INTERRUPT_CONTROLLER ++ &driver::INTERRUPT_CONTROLLER +} diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception.rs @@ -2126,7 +2156,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/exception.rs 13_excep diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs --- 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs -@@ -73,10 +73,12 @@ +@@ -73,10 +73,11 @@ pub mod mmio { use super::*; @@ -2138,12 +2168,11 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi/memory.rs 13_exceptio + pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; + pub const GPIO_START: usize = START + GPIO_OFFSET; + pub const PL011_UART_START: usize = START + UART_OFFSET; -+ pub const LOCAL_INTERRUPT_CONTROLLER_START: usize = 0x4000_0000; + pub const END_INCLUSIVE: usize = 0x4000_FFFF; } /// Physical devices. -@@ -87,6 +89,8 @@ +@@ -87,6 +88,8 @@ pub const START: usize = 0xFE00_0000; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; @@ -2164,34 +2193,6 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/raspberrypi.rs 13_exceptions_part pub mod memory; //-------------------------------------------------------------------------------------------------- -@@ -17,8 +18,25 @@ - static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - --static PL011_UART: device_driver::PL011Uart = -- unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; -+static PL011_UART: device_driver::PL011Uart = unsafe { -+ device_driver::PL011Uart::new( -+ memory::map::mmio::PL011_UART_START, -+ exception::asynchronous::irq_map::PL011_UART, -+ ) -+}; -+ -+#[cfg(feature = "bsp_rpi3")] -+static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { -+ device_driver::InterruptController::new( -+ memory::map::mmio::LOCAL_INTERRUPT_CONTROLLER_START, -+ memory::map::mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START, -+ ) -+}; -+ -+#[cfg(feature = "bsp_rpi4")] -+static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { -+ device_driver::GICv2::new(memory::map::mmio::GICD_START, memory::map::mmio::GICC_START) -+}; - - //-------------------------------------------------------------------------------------------------- - // Public Code diff -uNr 12_integrated_testing/kernel/src/cpu/smp.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/cpu/smp.rs --- 12_integrated_testing/kernel/src/cpu/smp.rs @@ -2247,10 +2248,11 @@ diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_periphe diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs -@@ -8,7 +8,145 @@ +@@ -8,7 +8,153 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; ++use crate::bsp; +use core::{fmt, marker::PhantomData}; + //-------------------------------------------------------------------------------------------------- @@ -2394,6 +2396,13 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio + + ret +} ++ ++/// Return a reference to the IRQ manager. ++/// ++/// This is the IRQ manager used by the architectural interrupt handling code. ++pub fn irq_manager() -> &'static dyn interface::IRQManager { ++ bsp::exception::asynchronous::irq_manager() ++} diff -uNr 12_integrated_testing/kernel/src/lib.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs --- 12_integrated_testing/kernel/src/lib.rs @@ -2428,7 +2437,7 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; -@@ -43,15 +43,27 @@ +@@ -43,14 +43,27 @@ bsp::driver::driver_manager().post_device_driver_init(); // println! is usable from here on. @@ -2451,14 +2460,13 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera /// The main function running after the early init. fn kernel_main() -> ! { -- use bsp::console::console; -- use console::interface::All; +- use console::console; use driver::interface::DriverManager; + use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); -@@ -79,12 +91,9 @@ +@@ -78,12 +91,9 @@ info!(" {}. {}", i + 1, driver.compatible()); } @@ -2469,8 +2477,8 @@ diff -uNr 12_integrated_testing/kernel/src/main.rs 13_exceptions_part2_periphera - // Discard any spurious received characters before going into echo mode. - console().clear_rx(); - loop { -- let c = bsp::console::console().read_char(); -- bsp::console::console().write_char(c); +- let c = console().read_char(); +- console().write_char(c); - } + info!("Echoing input now"); + cpu::wait_forever(); @@ -2483,12 +2491,12 @@ diff -uNr 12_integrated_testing/kernel/src/panic_wait.rs 13_exceptions_part2_per //! A panic handler that infinitely waits. --use crate::{bsp, cpu}; -+use crate::{bsp, cpu, exception}; - use core::{fmt, panic::PanicInfo}; +-use crate::{cpu, println}; ++use crate::{cpu, exception, println}; + use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- -@@ -77,6 +77,8 @@ +@@ -61,6 +61,8 @@ fn panic(info: &PanicInfo) -> ! { use crate::time::interface::TimeManager; @@ -2733,7 +2741,7 @@ diff -uNr 12_integrated_testing/kernel/src/synchronization.rs 13_exceptions_part diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs --- 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs -@@ -0,0 +1,66 @@ +@@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -2746,12 +2754,13 @@ diff -uNr 12_integrated_testing/kernel/tests/04_exception_irq_sanity.rs 13_excep +#![reexport_test_harness_main = "test_main"] +#![test_runner(libkernel::test_runner)] + -+use libkernel::{bsp, cpu, exception}; ++use libkernel::{bsp, cpu, driver, exception}; +use test_macros::kernel_test; + +#[no_mangle] +unsafe fn kernel_init() -> ! { -+ bsp::console::qemu_bring_up_console(); ++ use driver::interface::DriverManager; ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + exception::handling_init(); + exception::asynchronous::local_irq_unmask(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs index 09a0cdf4..03c1fa0f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -114,6 +114,8 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety @@ -135,7 +137,7 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index c0dc838a..b5603b40 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 577470d4..d4acd275 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -28,6 +28,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -74,12 +75,14 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(_local_mmio_start_addr: usize, periph_mmio_start_addr: usize) -> Self { + pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { Self { periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), } @@ -92,7 +95,7 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 4d000ad5..a96ebf7e 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -216,18 +216,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -236,7 +233,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -384,7 +381,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -408,7 +411,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -418,11 +421,10 @@ impl driver::interface::DeviceDriver for PL011Uart { } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -478,6 +480,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs index 97656a27..50b36762 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs @@ -10,34 +10,6 @@ pub mod driver; pub mod exception; pub mod memory; -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - memory::map::mmio::PL011_UART_START, - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - memory::map::mmio::LOCAL_INTERRUPT_CONTROLLER_START, - memory::map::mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START, - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new(memory::map::mmio::GICD_START, memory::map::mmio::GICC_START) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs index eaef0b1f..0a630eef 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs @@ -4,45 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -/// -/// For the RPi, nothing needs to be done. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() {} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs index 1cf6d23c..568f1096 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,10 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{bsp::device_driver, driver}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,12 +22,25 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { + device_driver::PL011Uart::new( + mmio::PL011_UART_START, + exception::asynchronous::irq_map::PL011_UART, + ) +}; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + +#[cfg(feature = "bsp_rpi3")] +pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = + unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; + +#[cfg(feature = "bsp_rpi4")] +pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = + unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], }; //-------------------------------------------------------------------------------------------------- @@ -48,6 +64,9 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } + + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) {} } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..a13b2444 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::{bsp, bsp::driver, exception}; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -32,5 +32,5 @@ pub(in crate::bsp) mod irq_map { pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< IRQNumberType = bsp::device_driver::IRQNumber, > { - &super::super::INTERRUPT_CONTROLLER + &driver::INTERRUPT_CONTROLLER } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs index 51b334c0..a383c9fe 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory.rs @@ -77,7 +77,6 @@ pub(super) mod map { pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; pub const GPIO_START: usize = START + GPIO_OFFSET; pub const PL011_UART_START: usize = START + UART_OFFSET; - pub const LOCAL_INTERRUPT_CONTROLLER_START: usize = 0x4000_0000; pub const END_INCLUSIVE: usize = 0x4000_FFFF; } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs index e49e241f..c1fb0e53 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs index 8c5c5e16..c39e5eaf 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs @@ -48,5 +48,10 @@ pub mod interface { /// /// For example, device driver code that depends on other drivers already being online. fn post_device_driver_init(&self); + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs index fb1785c2..17938692 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs @@ -8,6 +8,7 @@ #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +use crate::bsp; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -150,3 +151,10 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Return a reference to the IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + bsp::exception::asynchronous::irq_manager() +} diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs index 58a939f1..c4b07809 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs @@ -178,8 +178,10 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs index dccb6cc2..e12a711f 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs @@ -11,15 +11,15 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs index 59ef4a7f..390cdee5 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,15 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs index 9be94acd..62908377 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs @@ -17,14 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs index f25ed645..3f4eae79 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,10 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; use memory::mmu::interface::MMU; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs index e1e02554..1204dca4 100644 --- a/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs +++ b/13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs @@ -10,12 +10,13 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception}; +use libkernel::{bsp, cpu, driver, exception}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - bsp::console::qemu_bring_up_console(); + use driver::interface::DriverManager; + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index 5d78e237..b5caac52 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -8,8 +8,7 @@ whole of the board's address space. - Instead, only ranges that are actually needed are mapped: - The `kernel binary` stays `identity mapped` for now. - - Device `MMIO regions` are remapped lazily (to a special reserved virtual address region) - during the device driver's `init()`. + - Device `MMIO regions` are remapped lazily (to a special reserved virtual address region). ## Table of Contents @@ -59,7 +58,8 @@ separation, this tutorial makes a start by changing the following things: parts that are needed will be mapped. 1. For now, the `kernel binary` stays identity mapped. This will be changed in the coming tutorials as it is a quite difficult and peculiar exercise to remap the kernel. -1. Device `MMIO regions` are lazily remapped during a device driver's `init()`. +1. Device `MMIO regions` are lazily remapped during device driver bringup (using the new + `DriverManage` function `instantiate_drivers()`). 1. A dedicated region of virtual addresses that we reserve using `BSP` code and the `linker script` is used for this. 1. We keep using `TTBR0` for the kernel translation tables for now. This will be changed when we @@ -232,43 +232,111 @@ pub unsafe fn kernel_map_binary() -> Result<(), &'static str> { } ``` -Another user of the new APIs are device drivers, which now expect an `MMIODescriptor` type instead -of a raw address. The following is an example for the `UART`: +Another user of the new APIs is the **driver subsystem**. As has been said in the introduction, the +goal is to remap the `MMIO` regions of the drivers. To achieve this in a seamless way, some changes +to the architecture of the driver subsystem were needed. + +Until now, the drivers were `static instances` which had their `MMIO addresses` statically set in +the constructor. This was fine, because even if virtual memory was activated, only `identity +mapping` was used, so the hardcoded addresses would be valid with and without the MMU being active. + +With `remapped MMIO addresses`, this is not possible anymore, since the remapping will only happen +at runtime. Therefore, the new approach is to defer the whole instantiation of the drivers until the +remapped addresses are known. To achieve this, in `src/bsp/raspberrypi/drivers.rs`, the static +driver instances are now wrapped into a `MaybeUninit` (and are also `mut` now): ```rust -impl PL011Uart { - /// Create an instance. - pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, - irq_number: bsp::device_driver::IRQNumber, - ) -> Self { - Self { - // omitted for brevity. - } +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); +``` + +`BSPDriverManager` implements the new `instantiate_drivers()` interface function, which will be +called early during `kernel_init()`, short after virtual memory has been activated: + +```rust +unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; + + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } ``` -When the kernel calls the driver's implementation of `driver::interface::DeviceDriver::init()` -during kernel boot, the MMIO Descriptor is used to remap the MMIO region on demand: +As can be seen, for each driver, this `BSP` code calls a dedicated instantiation function. In this +tutorial text, only the `UART` will be discussed in detail: ```rust -unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; +unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } - // omitted for brevity. + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); Ok(()) } ``` +A couple of things are happening here. First, an `MMIODescriptor` is created and then used to remap +the MMIO region using `memory::mmu::kernel_map_mmio()`. This function will be discussed in detail in +the next chapter. What's important for now is that it returns the new `Virtual Address` of the +remapped MMIO region. The constructor of the `UART` driver now also expects a virtual address. + +Next, a new instance of the `PL011Uart` driver is created, and written into the `PL011_UART` global +variable (remember, it is defined as `MaybeUninit = +MaybeUninit::uninit()`). Meaning, after this line of code, `PL011_UART` is properly initialized. + +Another new feature is the function `uart_post_init()`, which is supplied to the UART constructor. +This is a callback that will be called by the UART driver when it concludes its `init()` function +(remember that the driver's init functions are called from `kernel_init()`). This callback, in turn, +registers the `PL011_UART` as the new console of the kernel. + +A look into `src/console.rs` should make clear what is happening. The classic `console::console()` +now dynamically points to whoever registered itself using the `console::register_console()` +function, instead of using a hardcoded static reference (from the `BSP`). This has been introduced +to accommodate the run-time instantiation of the device drivers (the same feature has been +implemented for the `IRQManager` as well). Until `console::register_console()` has been called for +the first time, an instance of the newly introduced `NullConsole` is used as the default. +`NullConsole` implements all the console traits, but does nothing. It discards outputs, and returns +dummy input. For example, should one of the printing macros be called before the UART driver has +been instantiated and registered, the kernel does not need to crash because the driver is not +brought up yet. Instead, it can just discards the output. With this new scheme of things, it is +possible to safely switch global references like the UART or the IRQ Manager at runtime. + +That all the post-driver-init work has now been moved to callbacks is motivated by the idea that +this fully enables a driver once it has concluded its `init()` function, and not only after all the +drivers have been init'ed and then the post-init code would be called, as earlier. In our example, +printing through the UART will now be available already before the interrupt controller driver runs +its init function. + ### MMIO Virtual Address Allocation -Peeking inside `memory::mmu::kernel_map_mmio()`, we can see that a `virtual address region` is -obtained from an `allocator` before remapping: +Getting back to the remapping part, let's peek inside `memory::mmu::kernel_map_mmio()`. We can see +that a `virtual address region` is obtained from an `allocator` before remapping: ```rust pub unsafe fn kernel_map_mmio( @@ -296,7 +364,7 @@ pub unsafe fn kernel_map_mmio( } ``` -This allocator is defined and implemented in the added file `src/memory/mmu/paeg_alloc.rs`. Like +This allocator is defined and implemented in the added file `src/memory/mmu/page_alloc.rs`. Like other parts of the mapping code, its implementation makes use of the newly introduced `PageAddress` and `MemoryRegion` types (in [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs)), but apart from that is rather straight @@ -339,13 +407,13 @@ the VA range. ### Supporting Changes -There's a couple of changes not covered in this tutorial text, but the reader should ideally skim -through them: +There's a couple of changes more not covered in this tutorial text, but the reader should ideally +skim through them: - [`src/memory.rs`](kernel/src/memory.rs) and - [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs) introduce a couple of supporting - types, like`Address`, `PageAddress` and `MemoryRegion`. It is worth reading - their implementations. + [`src/memory/mmu/types.rs`](kernel/src/memory/mmu/types.rs) introduce supporting types, + like`Address`, `PageAddress` and `MemoryRegion`. It is worth reading their + implementations. - [`src/memory/mmu/mapping_record.rs`](kernel/src/memory/mmu/mapping_record.rs) provides the generic kernel code's way of tracking previous memory mappings for use cases such as reusing existing mappings (in case of drivers that have their MMIO ranges in the same `64 KiB` page) or printing @@ -375,22 +443,22 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 67 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[MP] ⏩ Pushing 65 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.758253] mingo version 0.14.0 -[ 0.758460] Booting on: Raspberry Pi 3 -[ 0.758915] MMU online: -[ 0.759208] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.760952] Virtual Physical Size Attr Entity -[ 0.762696] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.764441] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 0.766044] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 0.767658] 0x0000_0000_0009_0000..0x0000_0000_000d_ffff --> 0x00_0009_0000..0x00_000d_ffff | 320 KiB | C RW XN | Kernel data and bss -[ 0.769229] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 0.770680] | BCM PL011 UART -[ 0.772197] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 0.773941] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.740694] mingo version 0.14.0 +[ 0.740902] Booting on: Raspberry Pi 3 +[ 0.741357] MMU online: +[ 0.741649] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.743393] Virtual Physical Size Attr Entity +[ 0.745138] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.746883] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 0.748486] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 0.750099] 0x0000_0000_0009_0000..0x0000_0000_000e_ffff --> 0x00_0009_0000..0x00_000e_ffff | 384 KiB | C RW XN | Kernel data and bss +[ 0.751670] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 0.753187] | BCM GPIO +[ 0.754638] 0x0000_0000_0010_0000..0x0000_0000_0010_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 0.756264] ------------------------------------------------------------------------------------------------------------------------------------------- ``` Raspberry Pi 4: @@ -412,24 +480,23 @@ Minipush 1.0 Raspberry Pi 4 [ML] Requesting binary -[MP] ⏩ Pushing 74 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 +[MP] ⏩ Pushing 65 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [ML] Loaded! Executing the payload now -[ 0.842275] mingo version 0.14.0 -[ 0.842308] Booting on: Raspberry Pi 4 -[ 0.842763] MMU online: -[ 0.843055] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.844800] Virtual Physical Size Attr Entity -[ 0.846544] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 0.848288] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 0.849892] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 0.851505] 0x0000_0000_0009_0000..0x0000_0000_000d_ffff --> 0x00_0009_0000..0x00_000d_ffff | 320 KiB | C RW XN | Kernel data and bss -[ 0.853076] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 0.854528] | BCM PL011 UART -[ 0.856045] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD -[ 0.857453] | GICC -[ 0.858862] ------------------------------------------------------------------------------------------------------------------------------------------- - +[ 0.736136] mingo version 0.14.0 +[ 0.736170] Booting on: Raspberry Pi 4 +[ 0.736625] MMU online: +[ 0.736918] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.738662] Virtual Physical Size Attr Entity +[ 0.740406] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 0.742151] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 0.743754] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 0.745368] 0x0000_0000_0009_0000..0x0000_0000_000d_ffff --> 0x00_0009_0000..0x00_000d_ffff | 320 KiB | C RW XN | Kernel data and bss +[ 0.746938] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 0.748455] | BCM GPIO +[ 0.749907] 0x0000_0000_000f_0000..0x0000_0000_000f_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICv2 GICD +[ 0.751380] | GICV2 GICC +[ 0.752853] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -807,455 +874,235 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/_arch/aarch64/memory/mm diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs -@@ -4,7 +4,9 @@ +@@ -4,7 +4,11 @@ //! GICC Driver - GIC CPU interface. -use crate::{bsp::device_driver::common::MMIODerefWrapper, exception}; +use crate::{ -+ bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, ++ bsp::device_driver::common::MMIODerefWrapper, ++ exception, ++ memory::{Address, Virtual}, +}; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, -@@ -60,12 +62,13 @@ - - /// Representation of the GIC CPU interface. - pub struct GICC { -- registers: Registers, -+ registers: InitStateLock, - } - - //-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -+use crate::synchronization::interface::ReadWriteEx; - - impl GICC { - /// Create an instance. -@@ -75,10 +78,15 @@ +@@ -73,7 +77,7 @@ + /// # Safety + /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { -- registers: Registers::new(mmio_start_addr), -+ registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } - } - -+ pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { -+ self.registers -+ .write(|regs| *regs = Registers::new(new_mmio_start_addr)); -+ } -+ - /// Accept interrupts of any priority. - /// - /// Quoting the GICv2 Architecture Specification: -@@ -91,7 +99,9 @@ - /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead - /// of `&mut self`. - pub fn priority_accept_all(&self) { -- self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. -+ self.registers.read(|regs| { -+ regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. -+ }); - } - - /// Enable the interface - start accepting IRQs. -@@ -101,7 +111,9 @@ - /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead - /// of `&mut self`. - pub fn enable(&self) { -- self.registers.CTLR.write(CTLR::Enable::SET); -+ self.registers.read(|regs| { -+ regs.CTLR.write(CTLR::Enable::SET); -+ }); - } - - /// Extract the number of the highest-priority pending IRQ. -@@ -117,7 +129,8 @@ - &self, - _ic: &exception::asynchronous::IRQContext<'irq_context>, - ) -> usize { -- self.registers.IAR.read(IAR::InterruptID) as usize -+ self.registers -+ .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) - } - - /// Complete handling of the currently active IRQ. -@@ -136,6 +149,8 @@ - irq_number: u32, - _ic: &exception::asynchronous::IRQContext<'irq_context>, - ) { -- self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); -+ self.registers.read(|regs| { -+ regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); -+ }); - } - } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs -@@ -8,8 +8,9 @@ +@@ -8,7 +8,9 @@ //! - SPI - Shared Peripheral Interrupt. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, state, synchronization, -- synchronization::IRQSafeNullLock, + bsp::device_driver::common::MMIODerefWrapper, ++ memory::{Address, Virtual}, + state, synchronization, -+ synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ - interfaces::{Readable, Writeable}, -@@ -83,7 +84,7 @@ - shared_registers: IRQSafeNullLock, - - /// Access to banked registers is unguarded. -- banked_registers: BankedRegisters, -+ banked_registers: InitStateLock, - } - - //-------------------------------------------------------------------------------------------------- -@@ -120,6 +121,7 @@ - //-------------------------------------------------------------------------------------------------- - // Public Code - //-------------------------------------------------------------------------------------------------- -+use crate::synchronization::interface::ReadWriteEx; - use synchronization::interface::Mutex; - - impl GICD { -@@ -131,10 +133,17 @@ - pub const unsafe fn new(mmio_start_addr: usize) -> Self { +@@ -128,7 +130,7 @@ + /// # Safety + /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), -- banked_registers: BankedRegisters::new(mmio_start_addr), -+ banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), - } - } - -+ pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { -+ self.shared_registers -+ .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); -+ self.banked_registers -+ .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); -+ } -+ - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. - /// - /// Quoting the GICv2 Architecture Specification: -@@ -142,7 +151,8 @@ - /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that - /// corresponds only to the processor reading the register." - fn local_gic_target_mask(&self) -> u32 { -- self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) -+ self.banked_registers -+ .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) - } - - /// Route all SPIs to the boot core and enable the distributor. -@@ -181,10 +191,10 @@ - // Check if we are handling a private or shared IRQ. - match irq_num { - // Private. -- 0..=31 => { -- let enable_reg = &self.banked_registers.ISENABLER; -+ 0..=31 => self.banked_registers.read(|regs| { -+ let enable_reg = ®s.ISENABLER; - enable_reg.set(enable_reg.get() | enable_bit); -- } -+ }), - // Shared. - _ => { - let enable_reg_index_shared = enable_reg_index - 1; + banked_registers: BankedRegisters::new(mmio_start_addr), diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs -@@ -79,7 +79,8 @@ +@@ -79,7 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitStateLock}; -+use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -+use core::sync::atomic::{AtomicBool, Ordering}; ++use crate::{ ++ bsp, cpu, driver, exception, ++ memory::{Address, Virtual}, ++ synchronization, ++ synchronization::InitStateLock, ++}; //-------------------------------------------------------------------------------------------------- // Private Definitions -@@ -96,12 +97,18 @@ +@@ -104,6 +109,9 @@ - /// Representation of the GIC. - pub struct GICv2 { -+ gicd_mmio_descriptor: memory::mmu::MMIODescriptor, -+ gicc_mmio_descriptor: memory::mmu::MMIODescriptor, -+ - /// The Distributor. - gicd: gicd::GICD, - - /// The CPU Interface. - gicc: gicc::GICC, - -+ /// Have the MMIO regions been remapped yet? -+ is_mmio_remapped: AtomicBool, -+ /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, ++ ++ /// Callback to be invoked after successful init. ++ post_init_callback: fn(), } -@@ -118,11 +125,17 @@ - /// + + //-------------------------------------------------------------------------------------------------- +@@ -121,11 +129,16 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(gicd_mmio_start_addr: usize, gicc_mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. + pub const unsafe fn new( -+ gicd_mmio_descriptor: memory::mmu::MMIODescriptor, -+ gicc_mmio_descriptor: memory::mmu::MMIODescriptor, ++ gicd_mmio_start_addr: Address, ++ gicc_mmio_start_addr: Address, ++ post_init_callback: fn(), + ) -> Self { Self { -- gicd: gicd::GICD::new(gicd_mmio_start_addr), -- gicc: gicc::GICC::new(gicc_mmio_start_addr), -+ gicd_mmio_descriptor, -+ gicc_mmio_descriptor, -+ gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), -+ gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), -+ is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), ++ post_init_callback, } } -@@ -139,6 +152,20 @@ - } + } +@@ -148,6 +161,8 @@ + self.gicc.priority_accept_all(); + self.gicc.enable(); - unsafe fn init(&self) -> Result<(), &'static str> { -+ let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); -+ if !remapped { -+ // GICD -+ let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; -+ self.gicd.set_mmio(virt_addr.as_usize()); -+ -+ // GICC -+ virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; -+ self.gicc.set_mmio(virt_addr.as_usize()); -+ -+ // Conclude remapping. -+ self.is_mmio_remapped.store(true, Ordering::Relaxed); -+ } ++ (self.post_init_callback)(); + - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { - self.gicd.boot_core_init(); - } + Ok(()) + } + } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs -@@ -5,9 +5,10 @@ +@@ -5,7 +5,10 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, synchronization, -+ bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, ++ bsp::device_driver::common::MMIODerefWrapper, ++ driver, ++ memory::{Address, Virtual}, ++ synchronization, synchronization::IRQSafeNullLock, }; -+use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ - interfaces::{ReadWriteable, Writeable}, - register_bitfields, register_structs, -@@ -121,6 +122,8 @@ - +@@ -119,6 +122,7 @@ /// Representation of the GPIO HW. pub struct GPIO { -+ mmio_descriptor: memory::mmu::MMIODescriptor, -+ virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, ++ post_init_callback: fn(), } -@@ -140,6 +143,19 @@ - } - } - -+ /// Init code. -+ /// -+ /// # Safety -+ /// -+ /// - The user must ensure to provide a correct MMIO start address. -+ pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { -+ if let Some(addr) = new_mmio_start_addr { -+ self.registers = Registers::new(addr); -+ } -+ -+ Ok(()) -+ } -+ - /// Disable pull-up/down on pins 14 and 15. - #[cfg(feature = "bsp_rpi3")] - fn disable_pud_14_15_bcm2837(&mut self) { -@@ -194,10 +210,12 @@ + //-------------------------------------------------------------------------------------------------- +@@ -131,7 +135,7 @@ + /// # Safety /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + } +@@ -198,9 +202,10 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. -+ pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { -- inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), -+ mmio_descriptor, -+ virt_mmio_start_addr: AtomicUsize::new(0), -+ inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), ++ post_init_callback, } } -@@ -216,4 +234,26 @@ +@@ -219,4 +224,10 @@ fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } + + unsafe fn init(&self) -> Result<(), &'static str> { -+ let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; -+ -+ self.inner -+ .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; -+ -+ self.virt_mmio_start_addr -+ .store(virt_addr.as_usize(), Ordering::Relaxed); ++ (self.post_init_callback)(); + + Ok(()) -+ } -+ -+ fn virt_mmio_start_addr(&self) -> Option { -+ let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); -+ -+ if addr == 0 { -+ return None; -+ } -+ -+ Some(addr) + } } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs -@@ -7,7 +7,7 @@ +@@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - exception, synchronization, -+ driver, exception, memory, synchronization, ++ exception, ++ memory::{Address, Virtual}, ++ synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ -@@ -55,11 +55,13 @@ - - /// Representation of the peripheral interrupt controller. - pub struct PeripheralIC { -+ mmio_descriptor: memory::mmu::MMIODescriptor, -+ - /// Access to write registers is guarded with a lock. - wo_registers: IRQSafeNullLock, - - /// Register read access is unguarded. -- ro_registers: ReadOnlyRegisters, -+ ro_registers: InitStateLock, - - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. - handler_table: InitStateLock, -@@ -74,21 +76,26 @@ - /// +@@ -75,7 +77,7 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. -+ pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { -+ let addr = mmio_descriptor.start_addr().as_usize(); -+ ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { -- wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), -- ro_registers: ReadOnlyRegisters::new(mmio_start_addr), -+ mmio_descriptor, -+ wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), -+ ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), - handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), - } - } - - /// Query the list of pending IRQs. - fn pending_irqs(&self) -> PendingIRQs { -- let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) -- | u64::from(self.ro_registers.PENDING_1.get()); -+ self.ro_registers.read(|regs| { -+ let pending_mask: u64 = -+ (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); - -- PendingIRQs::new(pending_mask) -+ PendingIRQs::new(pending_mask) -+ }) - } - } - -@@ -97,6 +104,24 @@ - //------------------------------------------------------------------------------ - use synchronization::interface::{Mutex, ReadWriteEx}; - -+impl driver::interface::DeviceDriver for PeripheralIC { -+ fn compatible(&self) -> &'static str { -+ "BCM Peripheral Interrupt Controller" -+ } -+ -+ unsafe fn init(&self) -> Result<(), &'static str> { -+ let virt_addr = -+ memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); -+ -+ self.wo_registers -+ .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); -+ self.ro_registers -+ .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); -+ -+ Ok(()) -+ } -+} -+ - impl exception::asynchronous::interface::IRQManager for PeripheralIC { - type IRQNumberType = PeripheralIRQ; - + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs -@@ -6,7 +6,7 @@ +@@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception}; -+use crate::{driver, exception, memory}; ++use crate::{ ++ driver, exception, ++ memory::{Address, Virtual}, ++}; //-------------------------------------------------------------------------------------------------- // Private Definitions -@@ -78,10 +78,13 @@ - /// +@@ -37,6 +40,7 @@ + /// Representation of the Interrupt Controller. + pub struct InterruptController { + periph: peripheral_ic::PeripheralIC, ++ post_init_callback: fn(), + } + + //-------------------------------------------------------------------------------------------------- +@@ -82,9 +86,13 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. -- pub const unsafe fn new(_local_mmio_start_addr: usize, periph_mmio_start_addr: usize) -> Self { -+ /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(periph_mmio_start_addr: usize) -> Self { + pub const unsafe fn new( -+ _local_mmio_descriptor: memory::mmu::MMIODescriptor, -+ periph_mmio_descriptor: memory::mmu::MMIODescriptor, ++ periph_mmio_start_addr: Address, ++ post_init_callback: fn(), + ) -> Self { Self { -- periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), -+ periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), ++ post_init_callback, } } } -@@ -94,6 +97,10 @@ +@@ -97,6 +105,12 @@ fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } + + unsafe fn init(&self) -> Result<(), &'static str> { -+ self.periph.init() ++ (self.post_init_callback)(); ++ ++ Ok(()) + } } @@ -1264,175 +1111,363 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs -@@ -10,10 +10,13 @@ +@@ -10,8 +10,12 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, -+ bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, +- synchronization, synchronization::IRQSafeNullLock, ++ bsp, ++ bsp::device_driver::common::MMIODerefWrapper, ++ console, cpu, driver, exception, ++ memory::{Address, Virtual}, ++ synchronization, ++ synchronization::IRQSafeNullLock, }; --use core::fmt; -+use core::{ -+ fmt, -+ sync::atomic::{AtomicUsize, Ordering}, -+}; + use core::fmt; use tock_registers::{ - interfaces::{Readable, Writeable}, - register_bitfields, register_structs, -@@ -231,6 +234,8 @@ - - /// Representation of the UART. +@@ -230,6 +234,7 @@ pub struct PL011Uart { -+ mmio_descriptor: memory::mmu::MMIODescriptor, -+ virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, ++ post_init_callback: fn(), } -@@ -270,7 +275,15 @@ - /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. - /// - /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16modulo`. -- pub fn init(&mut self) { -+ /// -+ /// # Safety -+ /// -+ /// - The user must ensure to provide a correct MMIO start address. -+ pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { -+ if let Some(addr) = new_mmio_start_addr { -+ self.registers = Registers::new(addr); -+ } -+ - // Execution can arrive here while there are still characters queued in the TX FIFO and - // actively being sent out by the UART hardware. If the UART is turned off in this case, - // those queued characters would be lost. -@@ -312,6 +325,8 @@ - self.registers - .CR - .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); -+ -+ Ok(()) - } - /// Send a character. -@@ -389,13 +404,18 @@ + //-------------------------------------------------------------------------------------------------- +@@ -242,7 +247,7 @@ + /// # Safety /// + /// - The user must ensure to provide a correct MMIO start address. +- pub const unsafe fn new(mmio_start_addr: usize) -> Self { ++ pub const unsafe fn new(mmio_start_addr: Address) -> Self { + Self { + registers: Registers::new(mmio_start_addr), + chars_written: 0, +@@ -393,13 +398,16 @@ /// # Safety /// -- /// - The user must ensure to provide a correct MMIO start address. -+ /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. + /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_start_addr: usize, -+ mmio_descriptor: memory::mmu::MMIODescriptor, ++ mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, ++ post_init_callback: fn(), ) -> Self { Self { -- inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), -+ mmio_descriptor, -+ virt_mmio_start_addr: AtomicUsize::new(0), -+ inner: IRQSafeNullLock::new(PL011UartInner::new( -+ mmio_descriptor.start_addr().as_usize(), -+ )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, ++ post_init_callback, } } -@@ -412,7 +432,13 @@ - } + } +@@ -416,6 +424,7 @@ unsafe fn init(&self) -> Result<(), &'static str> { -- self.inner.lock(|inner| inner.init()); -+ let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; -+ -+ self.inner -+ .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; -+ -+ self.virt_mmio_start_addr -+ .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); ++ (self.post_init_callback)(); Ok(()) } -@@ -431,6 +457,16 @@ - Ok(()) - } -+ -+ fn virt_mmio_start_addr(&self) -> Option { -+ let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); -+ -+ if addr == 0 { -+ return None; -+ } -+ -+ Some(addr) -+ } +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/common.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +@@ -4,6 +4,7 @@ + + //! Common device driver code. + ++use crate::memory::{Address, Virtual}; + use core::{marker::PhantomData, ops}; + + //-------------------------------------------------------------------------------------------------- +@@ -11,7 +12,7 @@ + //-------------------------------------------------------------------------------------------------- + + pub struct MMIODerefWrapper { +- start_addr: usize, ++ start_addr: Address, + phantom: PhantomData T>, } - impl console::interface::Write for PL011Uart { +@@ -21,7 +22,7 @@ + + impl MMIODerefWrapper { + /// Create an instance. +- pub const unsafe fn new(start_addr: usize) -> Self { ++ pub const unsafe fn new(start_addr: Address) -> Self { + Self { + start_addr, + phantom: PhantomData, +@@ -33,6 +34,6 @@ + type Target = T; + + fn deref(&self) -> &Self::Target { +- unsafe { &*(self.start_addr as *const _) } ++ unsafe { &*(self.start_addr.as_usize() as *const _) } + } + } diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/console.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs -@@ -5,7 +5,7 @@ - //! BSP console facilities. +@@ -1,16 +0,0 @@ +-// SPDX-License-Identifier: MIT OR Apache-2.0 +-// +-// Copyright (c) 2018-2022 Andre Richter +- +-//! BSP console facilities. +- +-use crate::console; +- +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-/// Return a reference to the console. +-pub fn console() -> &'static dyn console::interface::All { +- &super::driver::PL011_UART +-} - use super::memory; --use crate::{bsp::device_driver, console}; -+use crate::{bsp::device_driver, console, cpu, driver}; - use core::fmt; +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +@@ -5,7 +5,16 @@ + //! BSP driver support. - //-------------------------------------------------------------------------------------------------- -@@ -23,11 +23,25 @@ - /// - /// - Use only for printing during a panic. - pub unsafe fn panic_console_out() -> impl fmt::Write { -- let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); -- let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); -+ use driver::interface::DeviceDriver; - -+ let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); -+ let mut panic_uart = -+ device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -+ -+ // If remapping of the driver's MMIO already happened, take the remapped start address. -+ // Otherwise, take a chance with the default physical address. -+ let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); -+ let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ -+ panic_gpio -+ .init(maybe_gpio_mmio_start_addr) -+ .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); -- panic_uart.init(); -+ panic_uart -+ .init(maybe_uart_mmio_start_addr) -+ .unwrap_or_else(|_| cpu::wait_forever()); -+ - panic_uart + use super::{exception, memory::map::mmio}; +-use crate::{bsp::device_driver, driver}; ++use crate::{ ++ bsp::device_driver, ++ console, driver, exception as generic_exception, memory, ++ memory::mmu::MMIODescriptor, ++ synchronization::{interface::ReadWriteEx, InitStateLock}, ++}; ++use core::{ ++ mem::MaybeUninit, ++ sync::atomic::{AtomicBool, Ordering}, ++}; + + pub use device_driver::IRQNumber; + +@@ -15,35 +24,133 @@ + + /// Device Driver Manager type. + struct BSPDriverManager { +- device_drivers: [&'static (dyn DeviceDriver + Sync); 3], ++ device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, ++ init_done: AtomicBool, } + //-------------------------------------------------------------------------------------------------- +-// Global instances ++// Public Definitions + //-------------------------------------------------------------------------------------------------- + +-pub(super) static PL011_UART: device_driver::PL011Uart = unsafe { +- device_driver::PL011Uart::new( +- mmio::PL011_UART_START, +- exception::asynchronous::irq_map::PL011_UART, +- ) +-}; ++/// The number of active drivers provided by this BSP. ++pub const NUM_DRIVERS: usize = 3; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- -diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs ---- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/driver.rs -+++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs -@@ -46,7 +46,15 @@ - &self.device_drivers[..] - } +-static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; ++static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); ++static mut GPIO: MaybeUninit = MaybeUninit::uninit(); -- fn post_device_driver_init(&self) { -+ fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { -+ &self.device_drivers[0..=1] + #[cfg(feature = "bsp_rpi3")] +-pub(super) static INTERRUPT_CONTROLLER: device_driver::InterruptController = +- unsafe { device_driver::InterruptController::new(mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START) }; ++static mut INTERRUPT_CONTROLLER: MaybeUninit = ++ MaybeUninit::uninit(); + + #[cfg(feature = "bsp_rpi4")] +-pub(super) static INTERRUPT_CONTROLLER: device_driver::GICv2 = +- unsafe { device_driver::GICv2::new(mmio::GICD_START, mmio::GICC_START) }; ++static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { +- device_drivers: [&PL011_UART, &GPIO, &INTERRUPT_CONTROLLER], ++ device_drivers: InitStateLock::new([None; NUM_DRIVERS]), ++ init_done: AtomicBool::new(false), + }; + + //-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl BSPDriverManager { ++ unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { ++ let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); ++ let virt_addr = ++ memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn uart_post_init() { ++ console::register_console(unsafe { PL011_UART.assume_init_ref() }); ++ } ++ ++ PL011_UART.write(device_driver::PL011Uart::new( ++ virt_addr, ++ exception::asynchronous::irq_map::PL011_UART, ++ uart_post_init, ++ )); ++ ++ Ok(()) + } + -+ fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { -+ &self.device_drivers[2..] ++ unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { ++ let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); ++ let virt_addr = ++ memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn gpio_post_init() { ++ unsafe { GPIO.assume_init_ref().map_pl011_uart() }; ++ } ++ ++ GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); ++ ++ Ok(()) ++ } ++ ++ #[cfg(feature = "bsp_rpi3")] ++ unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { ++ let periph_mmio_descriptor = ++ MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); ++ let periph_virt_addr = memory::mmu::kernel_map_mmio( ++ device_driver::InterruptController::COMPATIBLE, ++ &periph_mmio_descriptor, ++ )?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn interrupt_controller_post_init() { ++ generic_exception::asynchronous::register_irq_manager(unsafe { ++ INTERRUPT_CONTROLLER.assume_init_ref() ++ }); ++ } ++ ++ INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( ++ periph_virt_addr, ++ interrupt_controller_post_init, ++ )); ++ ++ Ok(()) ++ } ++ ++ #[cfg(feature = "bsp_rpi4")] ++ unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { ++ let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); ++ let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; ++ ++ let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); ++ let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; ++ ++ // This is safe to do, because it is only called from the init'ed instance itself. ++ fn interrupt_controller_post_init() { ++ generic_exception::asynchronous::register_irq_manager(unsafe { ++ INTERRUPT_CONTROLLER.assume_init_ref() ++ }); ++ } ++ ++ INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( ++ gicd_virt_addr, ++ gicc_virt_addr, ++ interrupt_controller_post_init, ++ )); ++ ++ Ok(()) + } + -+ fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); ++ unsafe fn register_drivers(&self) { ++ self.device_drivers.write(|drivers| { ++ drivers[0] = Some(PL011_UART.assume_init_ref()); ++ drivers[1] = Some(GPIO.assume_init_ref()); ++ drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); ++ }); ++ } ++} ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- + +@@ -58,15 +165,34 @@ + use driver::interface::DeviceDriver; + + impl driver::interface::DriverManager for BSPDriverManager { +- fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { +- &self.device_drivers[..] ++ unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { ++ if self.init_done.load(Ordering::Relaxed) { ++ return Err("Drivers already instantiated"); ++ } ++ ++ self.instantiate_uart()?; ++ self.instantiate_gpio()?; ++ self.instantiate_interrupt_controller()?; ++ ++ self.register_drivers(); ++ ++ self.init_done.store(true, Ordering::Relaxed); ++ Ok(()) } +- fn post_device_driver_init(&self) { +- // Configure PL011Uart's output pins. +- GPIO.map_pl011_uart(); ++ fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { ++ self.device_drivers ++ .read(|drivers| drivers.map(|drivers| drivers.unwrap())) + } + + #[cfg(feature = "test_build")] +- fn qemu_bring_up_console(&self) {} ++ fn qemu_bring_up_console(&self) { ++ use crate::cpu; ++ ++ unsafe { ++ self.instantiate_uart() ++ .unwrap_or_else(|_| cpu::qemu_exit_failure()); ++ console::register_console(PL011_UART.assume_init_ref()); ++ }; ++ } + } + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/exception/asynchronous.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +@@ -4,7 +4,7 @@ + + //! BSP asynchronous exception handling. + +-use crate::{bsp, bsp::driver, exception}; ++use crate::bsp; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -23,14 +23,3 @@ + + pub const PL011_UART: IRQNumber = IRQNumber::new(153); + } +- +-//-------------------------------------------------------------------------------------------------- +-// Public Code +-//-------------------------------------------------------------------------------------------------- +- +-/// Return a reference to the IRQ manager. +-pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< +- IRQNumberType = bsp::device_driver::IRQNumber, +-> { +- &driver::INTERRUPT_CONTROLLER +-} + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/kernel.ld +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld @@ -1845,7 +1880,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. } //-------------------------------------------------------------------------------------------------- -@@ -50,35 +91,26 @@ +@@ -50,34 +91,23 @@ /// The board's physical memory map. #[rustfmt::skip] pub(super) mod map { @@ -1877,7 +1912,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. - pub const PERIPHERAL_INTERRUPT_CONTROLLER_START: usize = START + 0x0000_B200; - pub const GPIO_START: usize = START + GPIO_OFFSET; - pub const PL011_UART_START: usize = START + UART_OFFSET; -- pub const LOCAL_INTERRUPT_CONTROLLER_START: usize = 0x4000_0000; - pub const END_INCLUSIVE: usize = 0x4000_FFFF; + pub const PERIPHERAL_IC_START: Address = Address::new(0x3F00_B200); + pub const PERIPHERAL_IC_SIZE: usize = 0x24; @@ -1888,14 +1922,11 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. + pub const PL011_UART_START: Address = Address::new(0x3F20_1000); + pub const PL011_UART_SIZE: usize = 0x48; + -+ pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); -+ pub const LOCAL_IC_SIZE: usize = 0x100; -+ + pub const END: Address = Address::new(0x4001_0000); } /// Physical devices. -@@ -86,13 +118,22 @@ +@@ -85,13 +115,22 @@ pub mod mmio { use super::*; @@ -1924,7 +1955,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. } //-------------------------------------------------------------------------------------------------- -@@ -105,15 +146,76 @@ +@@ -104,15 +143,76 @@ /// /// - Value is provided by the linker script and must be trusted as-is. #[inline(always)] @@ -1932,19 +1963,21 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. - unsafe { __code_start.get() as usize } +fn virt_code_start() -> PageAddress { + PageAddress::from(unsafe { __code_start.get() as usize }) -+} -+ + } + +-/// Exclusive end page address of the code segment. +/// Size of the code segment. +/// -+/// # Safety -+/// -+/// - Value is provided by the linker script and must be trusted as-is. -+#[inline(always)] + /// # Safety + /// + /// - Value is provided by the linker script and must be trusted as-is. + #[inline(always)] +-fn code_end_exclusive() -> usize { +- unsafe { __code_end_exclusive.get() as usize } +fn code_size() -> usize { + unsafe { (__code_end_exclusive.get() as usize) - (__code_start.get() as usize) } - } - --/// Exclusive end page address of the code segment. ++} ++ +/// Start page address of the data segment. +#[inline(always)] +fn virt_data_start() -> PageAddress { @@ -1953,12 +1986,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. + +/// Size of the data segment. +/// - /// # Safety - /// - /// - Value is provided by the linker script and must be trusted as-is. - #[inline(always)] --fn code_end_exclusive() -> usize { -- unsafe { __code_end_exclusive.get() as usize } ++/// # Safety ++/// ++/// - Value is provided by the linker script and must be trusted as-is. ++#[inline(always)] +fn data_size() -> usize { + unsafe { (__data_end_exclusive.get() as usize) - (__data_start.get() as usize) } +} @@ -2010,51 +2041,14 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi/memory. diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/raspberrypi.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs -@@ -10,17 +10,20 @@ - pub mod exception; - pub mod memory; - -+use super::device_driver; -+use crate::memory::mmu::MMIODescriptor; -+use memory::map::mmio; -+ - //-------------------------------------------------------------------------------------------------- - // Global instances - //-------------------------------------------------------------------------------------------------- --use super::device_driver; - - static GPIO: device_driver::GPIO = -- unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; -+ unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - - static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( -- memory::map::mmio::PL011_UART_START, -+ MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) - }; -@@ -28,14 +31,17 @@ - #[cfg(feature = "bsp_rpi3")] - static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( -- memory::map::mmio::LOCAL_INTERRUPT_CONTROLLER_START, -- memory::map::mmio::PERIPHERAL_INTERRUPT_CONTROLLER_START, -+ MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), -+ MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) - }; +@@ -4,7 +4,6 @@ - #[cfg(feature = "bsp_rpi4")] - static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { -- device_driver::GICv2::new(memory::map::mmio::GICD_START, memory::map::mmio::GICC_START) -+ device_driver::GICv2::new( -+ MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), -+ MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), -+ ) - }; + //! Top-level BSP file for the Raspberry Pi 3 and 4. - //-------------------------------------------------------------------------------------------------- +-pub mod console; + pub mod cpu; + pub mod driver; + pub mod exception; diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_mem_part2_mmio_remap/kernel/src/common.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs @@ -2090,65 +2084,258 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/common.rs 14_virtual_me + (value + alignment - 1) & !(alignment - 1) +} +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/console/null_console.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs +@@ -0,0 +1,41 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Null console. ++ ++use super::interface; ++use core::fmt; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct NullConsole; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static NULL_CONSOLE: NullConsole = NullConsole {}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Private Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl interface::Write for NullConsole { ++ fn write_char(&self, _c: char) {} ++ ++ fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { ++ fmt::Result::Ok(()) ++ } ++ ++ fn flush(&self) {} ++} ++ ++impl interface::Read for NullConsole { ++ fn clear_rx(&self) {} ++} ++ ++impl interface::Statistics for NullConsole {} ++impl interface::All for NullConsole {} + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/console.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +@@ -4,7 +4,9 @@ + + //! System console. + +-use crate::bsp; ++mod null_console; ++ ++use crate::synchronization; + + //-------------------------------------------------------------------------------------------------- + // Public Definitions +@@ -55,12 +57,25 @@ + } + + //-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = ++ InitStateLock::new(&null_console::NULL_CONSOLE); ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- ++use synchronization::{interface::ReadWriteEx, InitStateLock}; ++ ++/// Register a new console. ++pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { ++ CUR_CONSOLE.write(|con| *con = new_console); ++} + +-/// Return a reference to the console. ++/// Return a reference to the currently registered console. + /// + /// This is the global console used by all printing macros. + pub fn console() -> &'static dyn interface::All { +- bsp::console::console() ++ CUR_CONSOLE.read(|con| *con) + } + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/driver.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs -@@ -31,6 +31,14 @@ - fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - Ok(()) - } -+ -+ /// After MMIO remapping, returns the new virtual start address. -+ /// -+ /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be -+ /// the case for more complex devices. This API will likely change in future tutorials. -+ fn virt_mmio_start_addr(&self) -> Option { -+ None -+ } - } +@@ -10,6 +10,8 @@ - /// Device driver management functions. -@@ -38,15 +46,17 @@ + /// Driver interfaces. + pub mod interface { ++ use crate::bsp; ++ + /// Device Driver functions. + pub trait DeviceDriver { + /// Return a compatibility string for identifying the driver. +@@ -37,17 +39,15 @@ + /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. -- /// -- /// # Safety -- /// +- /// Return a slice of references to all `BSP`-instantiated drivers. ++ /// Instantiate all drivers. + /// + /// # Safety + /// - /// - The order of devices is the order in which `DeviceDriver::init()` is called. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; +- fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ /// Must be called before `all_device_drivers`. ++ unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Initialization code that runs after driver init. -+ /// Return only those drivers needed for the BSP's early printing functionality. - /// +- /// - /// For example, device driver code that depends on other drivers already being online. - fn post_device_driver_init(&self); -+ /// For example, the default UART. -+ fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ /// Return a slice of references to all `BSP`-instantiated drivers. ++ fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; + + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous/null_irq_manager.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: MIT OR Apache-2.0 ++// ++// Copyright (c) 2022 Andre Richter ++ ++//! Null IRQ Manager. ++ ++use super::{interface, IRQContext, IRQDescriptor}; ++use crate::bsp; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Definitions ++//-------------------------------------------------------------------------------------------------- ++ ++pub struct NullIRQManager; ++ ++//-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; ++ ++//-------------------------------------------------------------------------------------------------- ++// Public Code ++//-------------------------------------------------------------------------------------------------- ++ ++impl interface::IRQManager for NullIRQManager { ++ type IRQNumberType = bsp::driver::IRQNumber; ++ ++ fn register_handler( ++ &self, ++ _irq_number: Self::IRQNumberType, ++ _descriptor: IRQDescriptor, ++ ) -> Result<(), &'static str> { ++ panic!("No IRQ Manager registered yet"); ++ } + -+ /// Return all drivers minus early-print drivers. -+ fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; ++ fn enable(&self, _irq_number: Self::IRQNumberType) { ++ panic!("No IRQ Manager registered yet"); ++ } + -+ /// Initialization code that runs after the early print driver init. -+ fn post_early_print_device_driver_init(&self); ++ fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { ++ panic!("No IRQ Manager registered yet"); ++ } ++} + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +@@ -7,8 +7,9 @@ + #[cfg(target_arch = "aarch64")] + #[path = "../_arch/aarch64/exception/asynchronous.rs"] + mod arch_asynchronous; ++mod null_irq_manager; + +-use crate::bsp; ++use crate::{bsp, synchronization}; + use core::{fmt, marker::PhantomData}; + + //-------------------------------------------------------------------------------------------------- +@@ -86,7 +87,7 @@ + ); + + /// Print list of registered handlers. +- fn print_handler(&self); ++ fn print_handler(&self) {} } } +@@ -95,8 +96,17 @@ + pub struct IRQNumber(usize); + + //-------------------------------------------------------------------------------------------------- ++// Global instances ++//-------------------------------------------------------------------------------------------------- ++ ++static CUR_IRQ_MANAGER: InitStateLock< ++ &'static (dyn interface::IRQManager + Sync), ++> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); ++ ++//-------------------------------------------------------------------------------------------------- + // Public Code + //-------------------------------------------------------------------------------------------------- ++use synchronization::{interface::ReadWriteEx, InitStateLock}; + + impl<'irq_context> IRQContext<'irq_context> { + /// Creates an IRQContext token. +@@ -152,9 +162,17 @@ + ret + } + +-/// Return a reference to the IRQ manager. ++/// Register a new IRQ manager. ++pub fn register_irq_manager( ++ new_manager: &'static (dyn interface::IRQManager ++ + Sync), ++) { ++ CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); ++} ++ ++/// Return a reference to the currently registered IRQ manager. + /// + /// This is the IRQ manager used by the architectural interrupt handling code. + pub fn irq_manager() -> &'static dyn interface::IRQManager { +- bsp::exception::asynchronous::irq_manager() ++ CUR_IRQ_MANAGER.read(|manager| *manager) + } + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs -@@ -113,8 +113,10 @@ +@@ -113,8 +113,11 @@ #![feature(asm_const)] #![feature(core_intrinsics)] #![feature(format_args_nl)] +#![feature(generic_const_exprs)] ++#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] +#![feature(step_trait)] #![feature(trait_alias)] #![no_std] // Testing -@@ -127,6 +129,7 @@ +@@ -127,6 +130,7 @@ mod synchronization; pub mod bsp; @@ -2156,19 +2343,32 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/lib.rs 14_virtual_mem_p pub mod console; pub mod cpu; pub mod driver; -@@ -179,6 +182,7 @@ - #[no_mangle] - unsafe fn kernel_init() -> ! { +@@ -181,7 +185,20 @@ + use driver::interface::DriverManager; + exception::handling_init(); ++ ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); ++ } ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. test_main(); + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs -@@ -27,21 +27,41 @@ +@@ -27,21 +27,31 @@ #[no_mangle] unsafe fn kernel_init() -> ! { use driver::interface::DriverManager; @@ -2185,38 +2385,32 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); -+ } + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); -+ -+ // Bring up the drivers needed for printing first. -+ for i in bsp::driver::driver_manager() -+ .early_print_device_drivers() -+ .iter() -+ { -+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -+ i.init().unwrap_or_else(|_| cpu::wait_forever()); - } -+ bsp::driver::driver_manager().post_early_print_device_driver_init(); -+ // Printing available again from here on. -- for i in bsp::driver::driver_manager().all_device_drivers().iter() { -+ // Now bring up the remaining drivers. -+ for i in bsp::driver::driver_manager() -+ .non_early_print_device_drivers() -+ .iter() -+ { ++ // Instantiate and init all device drivers. ++ if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { ++ panic!("Error instantiating drivers: {}", x); ++ } + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } } - bsp::driver::driver_manager().post_device_driver_init(); - // println! is usable from here on. ++ // Printing available again from here on. // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { -@@ -68,8 +88,8 @@ +@@ -63,13 +73,12 @@ + /// The main function running after the early init. + fn kernel_main() -> ! { + use driver::interface::DriverManager; +- use exception::asynchronous::interface::IRQManager; + info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -2227,11 +2421,20 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/main.rs 14_virtual_mem_ let (_, privilege_level) = exception::current_privilege_level(); info!("Current privilege level: {}", privilege_level); +@@ -92,7 +101,7 @@ + } + + info!("Registered IRQ handlers:"); +- bsp::exception::asynchronous::irq_manager().print_handler(); ++ exception::asynchronous::irq_manager().print_handler(); + + info!("Echoing input now"); + cpu::wait_forever(); diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_record.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs -@@ -0,0 +1,233 @@ +@@ -0,0 +1,249 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2020-2022 Andre Richter @@ -2310,6 +2513,19 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + Self { inner: [None; 12] } + } + ++ fn size(&self) -> usize { ++ self.inner.iter().filter(|x| x.is_some()).count() ++ } ++ ++ fn sort(&mut self) { ++ let upper_bound_exclusive = self.size(); ++ let entries = &mut self.inner[0..upper_bound_exclusive]; ++ ++ if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { ++ entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) ++ } ++ } ++ + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { + if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { + return Ok(x); @@ -2355,6 +2571,9 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory/mmu/mapping_reco + phys_region, + attr, + )); ++ ++ self.sort(); ++ + Ok(()) + } + @@ -3446,18 +3665,18 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs 14_virtual_me +//-------------------------------------------------------------------------------------------------- + +/// Metadata trait for marking the type of an address. -+pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} ++pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} + +/// Zero-sized type to mark a physical address. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Physical {} + +/// Zero-sized type to mark a virtual address. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub enum Virtual {} + +/// Generic address type. -+#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] ++#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub struct Address { + value: usize, + _address_type: PhantomData ATYPE>, @@ -3594,18 +3813,85 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/memory.rs 14_virtual_me + } +} +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/00_console_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +@@ -11,7 +11,7 @@ + /// Console tests should time out on the I/O harness in case of panic. + mod panic_wait_forever; + +-use libkernel::{bsp, console, cpu, driver, exception, print}; ++use libkernel::{bsp, console, cpu, driver, exception, memory, print}; + + #[no_mangle] + unsafe fn kernel_init() -> ! { +@@ -19,7 +19,20 @@ + use driver::interface::DriverManager; + + exception::handling_init(); ++ ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); ++ } ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ ++ memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. + + // Handshake + assert_eq!(console().read_char(), 'A'); + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/01_timer_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +@@ -11,7 +11,7 @@ + #![test_runner(libkernel::test_runner)] + + use core::time::Duration; +-use libkernel::{bsp, cpu, driver, exception, time, time::interface::TimeManager}; ++use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; + use test_macros::kernel_test; + + #[no_mangle] +@@ -19,7 +19,20 @@ + use driver::interface::DriverManager; + + exception::handling_init(); ++ ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); ++ } ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ ++ memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. + + // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + + diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_page_fault.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs -@@ -21,18 +21,40 @@ - +@@ -22,18 +22,29 @@ #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; - use memory::mmu::interface::MMU; -+ use libkernel::driver::interface::DriverManager; exception::handling_init(); -- bsp::console::qemu_bring_up_console(); +- bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); @@ -3627,17 +3913,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); -+ -+ // Bring up the drivers needed for printing first. -+ for i in bsp::driver::driver_manager() -+ .early_print_device_drivers() -+ .iter() -+ { -+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -+ i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ } -+ bsp::driver::driver_manager().post_early_print_device_driver_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. info!("Writing beyond mapped area to address 9 GiB..."); @@ -3646,15 +3922,14 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/02_exception_sync_pag diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_sanity.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs -@@ -30,18 +30,40 @@ - +@@ -31,18 +31,29 @@ #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; - use memory::mmu::interface::MMU; -+ use libkernel::driver::interface::DriverManager; exception::handling_init(); -- bsp::console::qemu_bring_up_console(); +- bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); @@ -3676,19 +3951,46 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/03_exception_restore_ + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); ++ // Printing available again from here on. + + info!("Making a dummy system call"); + + +diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +--- 13_exceptions_part2_peripheral_IRQs/kernel/tests/04_exception_irq_sanity.rs ++++ 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +@@ -10,15 +10,29 @@ + #![reexport_test_harness_main = "test_main"] + #![test_runner(libkernel::test_runner)] + +-use libkernel::{bsp, cpu, driver, exception}; ++use libkernel::{bsp, cpu, driver, exception, memory}; + use test_macros::kernel_test; + + #[no_mangle] + unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; +- bsp::driver::driver_manager().qemu_bring_up_console(); + + exception::handling_init(); + -+ // Bring up the drivers needed for printing first. -+ for i in bsp::driver::driver_manager() -+ .early_print_device_drivers() -+ .iter() -+ { -+ // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -+ i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); ++ let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { ++ Err(string) => panic!("Error mapping kernel binary: {}", string), ++ Ok(addr) => addr, ++ }; ++ ++ if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { ++ panic!("Enabling MMU failed: {}", e); + } -+ bsp::driver::driver_manager().post_early_print_device_driver_init(); ++ // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. ++ ++ memory::mmu::post_enable_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. ++ + exception::asynchronous::local_irq_unmask(); - info!("Making a dummy system call"); + test_main(); ``` diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index c75bf9be..00000000 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use super::memory; -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); - let mut panic_uart = - device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); - - // If remapping of the driver's MMIO already happened, take the remapped start address. - // Otherwise, take a chance with the default physical address. - let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); - let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); - - panic_gpio - .init(maybe_gpio_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(maybe_uart_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -/// -/// For the RPi, nothing needs to be done. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() {} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs index 660409bb..7d6e7911 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory.rs @@ -107,9 +107,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs index aeab8c22..ac57da95 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -181,9 +182,23 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. test_main(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs index 17edcfd9..7574522c 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/main.rs @@ -42,26 +42,16 @@ unsafe fn kernel_init() -> ! { memory::mmu::post_enable_init(); - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available again from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } } + // Printing available again from here on. // Let device drivers register and enable their handlers with the interrupt controller. for i in bsp::driver::driver_manager().all_device_drivers() { @@ -83,7 +73,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -112,7 +101,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs index dccb6cc2..a2338d2f 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs @@ -11,15 +11,28 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); - bsp::console::qemu_bring_up_console(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs index 59ef4a7f..4b4e90e4 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs @@ -11,13 +11,28 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); - bsp::console::qemu_bring_up_console(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs index e146aa3e..209517ac 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs @@ -17,11 +17,11 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { - use libkernel::driver::interface::DriverManager; + use driver::interface::DriverManager; exception::handling_init(); @@ -43,17 +43,7 @@ unsafe fn kernel_init() -> ! { // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); - } - bsp::driver::driver_manager().post_early_print_device_driver_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Printing available again from here on. info!("Writing beyond mapped area to address 9 GiB..."); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs index c6ff7b3d..babc31e2 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,7 +30,7 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { - use libkernel::driver::interface::DriverManager; + use driver::interface::DriverManager; exception::handling_init(); @@ -52,17 +52,7 @@ unsafe fn kernel_init() -> ! { // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); - } - bsp::driver::driver_manager().post_early_print_device_driver_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Printing available again from here on. info!("Making a dummy system call"); diff --git a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs index e1e02554..872cc008 100644 --- a/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ b/14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs @@ -10,14 +10,29 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { - bsp::console::qemu_bring_up_console(); + use driver::interface::DriverManager; exception::handling_init(); + + let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { + Err(string) => panic!("Error mapping kernel binary: {}", string), + Ok(addr) => addr, + }; + + if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { + panic!("Enabling MMU failed: {}", e); + } + // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. + + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); + // Printing available again from here on. + exception::asynchronous::local_irq_unmask(); test_main(); diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index b34c06b7..5a07f34b 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -775,22 +775,22 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 259 KiB ======================================🦀 100% 129 KiB/s Time: 00:00:02 +[MP] ⏩ Pushing 257 KiB ======================================🦀 100% 128 KiB/s Time: 00:00:02 [ML] Loaded! Executing the payload now -[ 2.891133] mingo version 0.15.0 -[ 2.891341] Booting on: Raspberry Pi 3 -[ 2.891796] MMU online: -[ 2.892088] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.893833] Virtual Physical Size Attr Entity -[ 2.895577] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.897322] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 2.898925] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 2.900538] 0x0000_0000_0009_0000..0x0000_0000_000c_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss -[ 2.902109] 0x0000_0000_000d_0000..0x0000_0000_000d_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 2.903561] | BCM PL011 UART -[ 2.905078] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 2.906822] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.866917] mingo version 0.15.0 +[ 2.867125] Booting on: Raspberry Pi 3 +[ 2.867580] MMU online: +[ 2.867872] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.869616] Virtual Physical Size Attr Entity +[ 2.871360] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.873105] 0x0000_0000_0000_0000..0x0000_0000_0007_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 2.874709] 0x0000_0000_0008_0000..0x0000_0000_0008_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 2.876322] 0x0000_0000_0009_0000..0x0000_0000_000c_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss +[ 2.877893] 0x0000_0000_000d_0000..0x0000_0000_000d_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 2.879410] | BCM GPIO +[ 2.880861] 0x0000_0000_000e_0000..0x0000_0000_000e_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 2.882487] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -1065,65 +1065,6 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/_arch/aarch64/memory/mmu/tr //-------------------------------------------------------------------------------------------------- -diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs ---- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/console.rs -+++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs -@@ -22,6 +22,7 @@ - /// # Safety - /// - /// - Use only for printing during a panic. -+#[cfg(not(feature = "test_build"))] - pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - -@@ -45,6 +46,27 @@ - panic_uart - } - -+/// Reduced version for test builds. -+/// -+/// # Safety -+/// -+/// - Use only for printing during a panic. -+#[cfg(feature = "test_build")] -+pub unsafe fn panic_console_out() -> impl fmt::Write { -+ use driver::interface::DeviceDriver; -+ -+ let mut panic_uart = -+ device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -+ -+ let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ -+ panic_uart -+ .init(maybe_uart_mmio_start_addr) -+ .unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ -+ panic_uart -+} -+ - /// Return a reference to the console. - pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -@@ -56,7 +78,15 @@ - - /// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps - /// than on real hardware due to QEMU's abstractions. --/// --/// For the RPi, nothing needs to be done. - #[cfg(feature = "test_build")] --pub fn qemu_bring_up_console() {} -+pub fn qemu_bring_up_console() { -+ use driver::interface::DeviceDriver; -+ -+ // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO -+ // addresses. -+ unsafe { -+ super::PL011_UART -+ .init() -+ .unwrap_or_else(|_| cpu::qemu_exit_failure()); -+ } -+} - diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld --- 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/kernel.ld +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld @@ -1371,10 +1312,35 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/raspberrypi/memory/mmu. + ); } +diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +--- 14_virtual_mem_part2_mmio_remap/kernel/src/lib.rs ++++ 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +@@ -185,20 +185,8 @@ + use driver::interface::DriverManager; + + exception::handling_init(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. + + test_main(); + + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs -@@ -17,31 +17,23 @@ +@@ -17,29 +17,17 @@ /// Early init code. /// @@ -1406,22 +1372,24 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/main.rs 15_virtual_mem_part - memory::mmu::post_enable_init(); -+ // Add the mapping records for the precomputed entries first, so that they appear on the top of -+ // the list. -+ bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); -+ - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() -@@ -51,7 +43,7 @@ - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. +@@ -51,7 +39,6 @@ + panic!("Error loading driver: {}: {}", i.compatible(), x); + } } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available again from here on. -+ // Printing available from here on. - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() + // Let device drivers register and enable their handlers with the interrupt controller. + for i in bsp::driver::driver_manager().all_device_drivers() { +@@ -60,6 +47,8 @@ + } + } + ++ bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); ++ + // Unmask interrupts on the boot CPU core. + exception::asynchronous::local_irq_unmask(); + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/translation_table.rs --- 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu/translation_table.rs @@ -1685,57 +1653,66 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/src/memory/mmu.rs 15_virtual_me diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/00_console_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs -@@ -11,7 +11,7 @@ - /// Console tests should time out on the I/O harness in case of panic. - mod panic_wait_forever; - --use libkernel::{bsp, console, cpu, exception, print}; -+use libkernel::{bsp, console, cpu, exception, memory, print}; - - #[no_mangle] - unsafe fn kernel_init() -> ! { -@@ -19,6 +19,7 @@ - use console::interface::*; +@@ -19,20 +19,8 @@ + use driver::interface::DriverManager; exception::handling_init(); -+ memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. // Handshake + assert_eq!(console().read_char(), 'A'); diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/01_timer_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs -@@ -11,12 +11,13 @@ - #![test_runner(libkernel::test_runner)] - - use core::time::Duration; --use libkernel::{bsp, cpu, exception, time, time::interface::TimeManager}; -+use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; - use test_macros::kernel_test; +@@ -19,20 +19,8 @@ + use driver::interface::DriverManager; - #[no_mangle] - unsafe fn kernel_init() -> ! { exception::handling_init(); -+ memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. + diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fault.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs -@@ -21,40 +21,12 @@ +@@ -24,28 +24,12 @@ + use driver::interface::DriverManager; - #[no_mangle] - unsafe fn kernel_init() -> ! { -- use libkernel::driver::interface::DriverManager; -- exception::handling_init(); -- -- // This line will be printed as the test header. -- println!("Testing synchronous exception handling by causing a page fault"); -- ++ memory::mmu::post_enable_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing synchronous exception handling by causing a page fault"); + - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { - Err(string) => { - info!("Error mapping kernel binary: {}", string); @@ -1750,39 +1727,27 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/02_exception_sync_page_fa - } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - -- // Bring up the drivers needed for printing first. -- for i in bsp::driver::driver_manager() -- .early_print_device_drivers() -- .iter() -- { -- // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -- i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); -- } -- bsp::driver::driver_manager().post_early_print_device_driver_init(); +- memory::mmu::post_enable_init(); +- bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. -+ // This line will be printed as the test header. -+ println!("Testing synchronous exception handling by causing a page fault"); - +- info!("Writing beyond mapped area to address 9 GiB..."); let big_addr: u64 = 9 * 1024 * 1024 * 1024; + core::ptr::read_volatile(big_addr as *mut u64); diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs -@@ -30,40 +30,12 @@ +@@ -33,28 +33,12 @@ + use driver::interface::DriverManager; - #[no_mangle] - unsafe fn kernel_init() -> ! { -- use libkernel::driver::interface::DriverManager; -- exception::handling_init(); -- -- // This line will be printed as the test header. -- println!("Testing exception restore"); -- ++ memory::mmu::post_enable_init(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + // This line will be printed as the test header. + println!("Testing exception restore"); + - let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { - Err(string) => { - info!("Error mapping kernel binary: {}", string); @@ -1797,42 +1762,41 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/03_exception_restore_sani - } - // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. - - memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); - -- // Bring up the drivers needed for printing first. -- for i in bsp::driver::driver_manager() -- .early_print_device_drivers() -- .iter() -- { -- // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. -- i.init().unwrap_or_else(|_| cpu::qemu_exit_failure()); -- } -- bsp::driver::driver_manager().post_early_print_device_driver_init(); +- memory::mmu::post_enable_init(); +- bsp::driver::driver_manager().qemu_bring_up_console(); - // Printing available again from here on. -+ // This line will be printed as the test header. -+ println!("Testing exception restore"); - +- info!("Making a dummy system call"); + // Calling this inside a function indirectly tests if the link register is restored properly. diff -uNr 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs --- 14_virtual_mem_part2_mmio_remap/kernel/tests/04_exception_irq_sanity.rs +++ 15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs -@@ -10,11 +10,12 @@ - #![reexport_test_harness_main = "test_main"] - #![test_runner(libkernel::test_runner)] +@@ -17,22 +17,10 @@ + unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; --use libkernel::{bsp, cpu, exception}; -+use libkernel::{bsp, cpu, exception, memory}; - use test_macros::kernel_test; +- exception::handling_init(); +- +- let phys_kernel_tables_base_addr = match memory::mmu::kernel_map_binary() { +- Err(string) => panic!("Error mapping kernel binary: {}", string), +- Ok(addr) => addr, +- }; +- +- if let Err(e) = memory::mmu::enable_mmu_and_caching(phys_kernel_tables_base_addr) { +- panic!("Enabling MMU failed: {}", e); +- } +- // Printing will silently fail from here on, because the driver's MMIO is not remapped yet. +- + memory::mmu::post_enable_init(); + bsp::driver::driver_manager().qemu_bring_up_console(); +- // Printing available again from here on. - #[no_mangle] - unsafe fn kernel_init() -> ! { -+ memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); ++ exception::handling_init(); + exception::asynchronous::local_irq_unmask(); - exception::handling_init(); + test_main(); diff -uNr 14_virtual_mem_part2_mmio_remap/Makefile 15_virtual_mem_part3_precomputed_tables/Makefile --- 14_virtual_mem_part2_mmio_remap/Makefile diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index f4105ed7..00000000 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use super::memory; -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); - let mut panic_uart = - device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); - - // If remapping of the driver's MMIO already happened, take the remapped start address. - // Otherwise, take a chance with the default physical address. - let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); - let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); - - panic_gpio - .init(maybe_gpio_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(maybe_uart_mmio_start_addr) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let mut panic_uart = - device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); - - let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); - - panic_uart - .init(maybe_uart_mmio_start_addr) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs index 660409bb..7d6e7911 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/memory.rs @@ -107,9 +107,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs index aeab8c22..1787ce02 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -181,9 +182,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs index 2d4b0977..feb84d9b 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs +++ b/15_virtual_mem_part3_precomputed_tables/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/16_virtual_mem_part4_higher_half_kernel/README.md b/16_virtual_mem_part4_higher_half_kernel/README.md index a9282d80..943273c0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/README.md +++ b/16_virtual_mem_part4_higher_half_kernel/README.md @@ -253,22 +253,22 @@ Minipush 1.0 Raspberry Pi 3 [ML] Requesting binary -[MP] ⏩ Pushing 259 KiB ======================================🦀 100% 129 KiB/s Time: 00:00:02 +[MP] ⏩ Pushing 257 KiB ======================================🦀 100% 128 KiB/s Time: 00:00:02 [ML] Loaded! Executing the payload now -[ 2.893480] mingo version 0.16.0 -[ 2.893687] Booting on: Raspberry Pi 3 -[ 2.894142] MMU online: -[ 2.894434] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.896179] Virtual Physical Size Attr Entity -[ 2.897923] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.899668] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 2.901282] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss -[ 2.902852] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 2.904455] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 2.905907] | BCM PL011 UART -[ 2.907424] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Peripheral Interrupt Controller -[ 2.909168] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.870248] mingo version 0.16.0 +[ 2.870456] Booting on: Raspberry Pi 3 +[ 2.870911] MMU online: +[ 2.871203] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.872947] Virtual Physical Size Attr Entity +[ 2.874691] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.876436] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 2.878050] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss +[ 2.879621] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_3f20_0000..0x00_3f20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 2.881137] | BCM GPIO +[ 2.882589] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_3f00_0000..0x00_3f00_ffff | 64 KiB | Dev RW XN | BCM Interrupt Controller +[ 2.884214] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 2.885818] ------------------------------------------------------------------------------------------------------------------------------------------- ``` Raspberry Pi 4: @@ -303,23 +303,23 @@ Minipush 1.0 Raspberry Pi 4 [ML] Requesting binary -[MP] ⏩ Pushing 266 KiB ======================================🦀 100% 133 KiB/s Time: 00:00:02 +[MP] ⏩ Pushing 257 KiB ======================================🦀 100% 128 KiB/s Time: 00:00:02 [ML] Loaded! Executing the payload now -[ 2.973300] mingo version 0.16.0 -[ 2.973334] Booting on: Raspberry Pi 4 -[ 2.973789] MMU online: -[ 2.974081] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.975825] Virtual Physical Size Attr Entity -[ 2.977569] ------------------------------------------------------------------------------------------------------------------------------------------- -[ 2.979314] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data -[ 2.980929] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss -[ 2.982499] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack -[ 2.984102] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM GPIO -[ 2.985554] | BCM PL011 UART -[ 2.987070] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICD -[ 2.988479] | GICC -[ 2.989887] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.871960] mingo version 0.16.0 +[ 2.871994] Booting on: Raspberry Pi 4 +[ 2.872449] MMU online: +[ 2.872742] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.874486] Virtual Physical Size Attr Entity +[ 2.876230] ------------------------------------------------------------------------------------------------------------------------------------------- +[ 2.877975] 0xffff_ffff_c000_0000..0xffff_ffff_c000_ffff --> 0x00_0008_0000..0x00_0008_ffff | 64 KiB | C RO X | Kernel code and RO data +[ 2.879589] 0xffff_ffff_c001_0000..0xffff_ffff_c004_ffff --> 0x00_0009_0000..0x00_000c_ffff | 256 KiB | C RW XN | Kernel data and bss +[ 2.881159] 0xffff_ffff_c005_0000..0xffff_ffff_c005_ffff --> 0x00_fe20_0000..0x00_fe20_ffff | 64 KiB | Dev RW XN | BCM PL011 UART +[ 2.882676] | BCM GPIO +[ 2.884128] 0xffff_ffff_c006_0000..0xffff_ffff_c006_ffff --> 0x00_ff84_0000..0x00_ff84_ffff | 64 KiB | Dev RW XN | GICv2 GICD +[ 2.885601] | GICV2 GICC +[ 2.887074] 0xffff_ffff_c086_0000..0xffff_ffff_c08d_ffff --> 0x00_0000_0000..0x00_0007_ffff | 512 KiB | C RW XN | Kernel boot-core stack +[ 2.888678] ------------------------------------------------------------------------------------------------------------------------------------------- ``` ## Diff to previous @@ -568,76 +568,6 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/_arch/aarch64/memor self.configure_translation_control(); -diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs ---- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/console.rs -+++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs -@@ -4,7 +4,6 @@ - - //! BSP console facilities. - --use super::memory; - use crate::{bsp::device_driver, console, cpu, driver}; - use core::fmt; - -@@ -26,21 +25,27 @@ - pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - -- let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START.as_usize()); -- let mut panic_uart = -- device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -- -- // If remapping of the driver's MMIO already happened, take the remapped start address. -- // Otherwise, take a chance with the default physical address. -- let maybe_gpio_mmio_start_addr = super::GPIO.virt_mmio_start_addr(); -- let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just -+ // park the CPU core in this case. -+ let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { -+ None => cpu::wait_forever(), -+ Some(x) => x, -+ }; -+ -+ let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { -+ None => cpu::wait_forever(), -+ Some(x) => x, -+ }; -+ -+ let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); -+ let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio -- .init(maybe_gpio_mmio_start_addr) -+ .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart -- .init(maybe_uart_mmio_start_addr) -+ .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -@@ -55,13 +60,14 @@ - pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - -- let mut panic_uart = -- device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START.as_usize()); -- -- let maybe_uart_mmio_start_addr = super::PL011_UART.virt_mmio_start_addr(); -+ let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { -+ None => cpu::wait_forever(), -+ Some(x) => x, -+ }; -+ let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart -- .init(maybe_uart_mmio_start_addr) -+ .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart - diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld --- 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/kernel.ld +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/kernel.ld @@ -799,7 +729,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/bsp/raspberrypi/mem diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/src/lib.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs -@@ -152,11 +152,6 @@ +@@ -153,11 +153,6 @@ ) } @@ -873,7 +803,7 @@ diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/src/memory/mmu.rs 16_vi diff -uNr 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs --- 15_virtual_mem_part3_precomputed_tables/kernel/tests/02_exception_sync_page_fault.rs +++ 16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs -@@ -28,8 +28,8 @@ +@@ -30,8 +30,8 @@ // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs index 662c91b9..fa6748a6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception}; +use crate::exception; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index a0d2e687..00000000 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just - // park the CPU core in this case. - let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs index 9e071726..f34009de 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/memory.rs @@ -111,9 +111,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs index c9c03792..f023d683 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -176,9 +177,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs index 0d2a1e63..33463e0a 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs +++ b/16_virtual_mem_part4_higher_half_kernel/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/17_kernel_symbols/Makefile b/17_kernel_symbols/Makefile index 41cecae3..ec71b493 100644 --- a/17_kernel_symbols/Makefile +++ b/17_kernel_symbols/Makefile @@ -215,7 +215,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) ##------------------------------------------------------------------------------ ## Generate the documentation ##------------------------------------------------------------------------------ -doc: +doc: clean $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open diff --git a/17_kernel_symbols/README.md b/17_kernel_symbols/README.md index 897e38cd..84378fff 100644 --- a/17_kernel_symbols/README.md +++ b/17_kernel_symbols/README.md @@ -269,12 +269,12 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/_arch/aarch64/excep //! //! crate::exception::arch_exception --use crate::{bsp, exception}; -+use crate::{bsp, exception, memory, symbols}; +-use crate::exception; ++use crate::{exception, memory, symbols}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ -@@ -262,6 +262,14 @@ +@@ -260,6 +260,14 @@ writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; @@ -332,7 +332,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/bsp/raspberrypi/mem diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_symbols/kernel/src/lib.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs +++ 17_kernel_symbols/kernel/src/lib.rs -@@ -137,6 +137,7 @@ +@@ -138,6 +138,7 @@ pub mod memory; pub mod print; pub mod state; @@ -731,6 +731,15 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/Makefile 17_kernel_symbols/Mak $(call color_progress_prefix, "Name") @echo $(KERNEL_BIN) $(call color_progress_prefix, "Size") +@@ -190,7 +215,7 @@ + ##------------------------------------------------------------------------------ + ## Generate the documentation + ##------------------------------------------------------------------------------ +-doc: ++doc: clean + $(call color_header, "Generating docs") + @$(DOC_CMD) --document-private-items --open + @@ -318,10 +343,19 @@ cd $(shell pwd) diff --git a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs index 6781758a..3672466c 100644 --- a/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs +++ b/17_kernel_symbols/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception, memory, symbols}; +use crate::{exception, memory, symbols}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -104,10 +104,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs +++ b/17_kernel_symbols/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index a0d2e687..00000000 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just - // park the CPU core in this case. - let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs index 01aa9441..32416e6c 100644 --- a/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs +++ b/17_kernel_symbols/kernel/src/bsp/raspberrypi/memory.rs @@ -113,9 +113,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/17_kernel_symbols/kernel/src/console.rs b/17_kernel_symbols/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/17_kernel_symbols/kernel/src/console.rs +++ b/17_kernel_symbols/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/17_kernel_symbols/kernel/src/console/null_console.rs b/17_kernel_symbols/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/17_kernel_symbols/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/17_kernel_symbols/kernel/src/driver.rs b/17_kernel_symbols/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/17_kernel_symbols/kernel/src/driver.rs +++ b/17_kernel_symbols/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous.rs b/17_kernel_symbols/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/17_kernel_symbols/kernel/src/exception/asynchronous.rs +++ b/17_kernel_symbols/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/17_kernel_symbols/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/17_kernel_symbols/kernel/src/lib.rs b/17_kernel_symbols/kernel/src/lib.rs index 8e38ad6f..e70468e5 100644 --- a/17_kernel_symbols/kernel/src/lib.rs +++ b/17_kernel_symbols/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -177,9 +178,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/17_kernel_symbols/kernel/src/main.rs b/17_kernel_symbols/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/17_kernel_symbols/kernel/src/main.rs +++ b/17_kernel_symbols/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/17_kernel_symbols/kernel/src/memory.rs b/17_kernel_symbols/kernel/src/memory.rs index f20719bb..64d8cf64 100644 --- a/17_kernel_symbols/kernel/src/memory.rs +++ b/17_kernel_symbols/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs +++ b/17_kernel_symbols/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/17_kernel_symbols/kernel/src/panic_wait.rs b/17_kernel_symbols/kernel/src/panic_wait.rs index 08d7d453..e4256b61 100644 --- a/17_kernel_symbols/kernel/src/panic_wait.rs +++ b/17_kernel_symbols/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/17_kernel_symbols/kernel/src/print.rs b/17_kernel_symbols/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/17_kernel_symbols/kernel/src/print.rs +++ b/17_kernel_symbols/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/17_kernel_symbols/kernel/tests/00_console_sanity.rs b/17_kernel_symbols/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/17_kernel_symbols/kernel/tests/00_console_sanity.rs +++ b/17_kernel_symbols/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/17_kernel_symbols/kernel/tests/01_timer_sanity.rs +++ b/17_kernel_symbols/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs index 0d2a1e63..33463e0a 100644 --- a/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs +++ b/17_kernel_symbols/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs +++ b/17_kernel_symbols/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs +++ b/17_kernel_symbols/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/18_backtrace/Makefile b/18_backtrace/Makefile index 85826c12..5d660332 100644 --- a/18_backtrace/Makefile +++ b/18_backtrace/Makefile @@ -217,7 +217,7 @@ $(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS) ##------------------------------------------------------------------------------ ## Generate the documentation ##------------------------------------------------------------------------------ -doc: +doc: clean $(call color_header, "Generating docs") @$(DOC_CMD) --document-private-items --open diff --git a/18_backtrace/README.md b/18_backtrace/README.md index c3cc1cc8..fd173703 100644 --- a/18_backtrace/README.md +++ b/18_backtrace/README.md @@ -228,7 +228,7 @@ match backtrace_res { Finally, we add printing of a backtrace to `panic!`: ```rust -panic_println!( +println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}\n\n\ @@ -909,7 +909,7 @@ diff -uNr 17_kernel_symbols/kernel/src/bsp/raspberrypi/memory/mmu.rs 18_backtrac diff -uNr 17_kernel_symbols/kernel/src/lib.rs 18_backtrace/kernel/src/lib.rs --- 17_kernel_symbols/kernel/src/lib.rs +++ 18_backtrace/kernel/src/lib.rs -@@ -128,6 +128,7 @@ +@@ -129,6 +129,7 @@ mod panic_wait; mod synchronization; @@ -967,20 +967,20 @@ diff -uNr 17_kernel_symbols/kernel/src/panic_wait.rs 18_backtrace/kernel/src/pan //! A panic handler that infinitely waits. --use crate::{bsp, cpu, exception}; -+use crate::{backtrace, bsp, cpu, exception}; - use core::{fmt, panic::PanicInfo}; +-use crate::{cpu, exception, println}; ++use crate::{backtrace, cpu, exception, println}; + use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- -@@ -91,6 +91,7 @@ - panic_println!( +@@ -75,6 +75,7 @@ + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ + {}\n\n\ {}", timestamp.as_secs(), timestamp.subsec_micros(), -@@ -98,6 +99,7 @@ +@@ -82,6 +83,7 @@ line, column, info.message().unwrap_or(&format_args!("")), @@ -1036,7 +1036,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rb 18_backtrace/ker diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/kernel/tests/05_backtrace_sanity.rs --- 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs +++ 18_backtrace/kernel/tests/05_backtrace_sanity.rs -@@ -0,0 +1,31 @@ +@@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1050,7 +1050,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{bsp, cpu, exception, memory}; ++use libkernel::{bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested() { @@ -1059,9 +1059,11 @@ diff -uNr 17_kernel_symbols/kernel/tests/05_backtrace_sanity.rs 18_backtrace/ker + +#[no_mangle] +unsafe fn kernel_init() -> ! { ++ use driver::interface::DriverManager; ++ + exception::handling_init(); + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); + @@ -1103,7 +1105,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rb 18_backtr diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs --- 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs +++ 18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs -@@ -0,0 +1,33 @@ +@@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1117,7 +1119,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{backtrace, bsp, cpu, exception, memory}; ++use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested() { @@ -1128,9 +1130,11 @@ diff -uNr 17_kernel_symbols/kernel/tests/06_backtrace_invalid_frame.rs 18_backtr + +#[no_mangle] +unsafe fn kernel_init() -> ! { ++ use driver::interface::DriverManager; ++ + exception::handling_init(); + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + nested(); + @@ -1171,7 +1175,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rb 18_backtra diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs --- 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs +++ 18_backtrace/kernel/tests/07_backtrace_invalid_link.rs -@@ -0,0 +1,38 @@ +@@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter @@ -1185,7 +1189,7 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra +/// Console tests should time out on the I/O harness in case of panic. +mod panic_wait_forever; + -+use libkernel::{backtrace, bsp, cpu, exception, memory}; ++use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; + +#[inline(never)] +fn nested_2() -> &'static str { @@ -1201,9 +1205,11 @@ diff -uNr 17_kernel_symbols/kernel/tests/07_backtrace_invalid_link.rs 18_backtra + +#[no_mangle] +unsafe fn kernel_init() -> ! { ++ use driver::interface::DriverManager; ++ + exception::handling_init(); + memory::mmu::post_enable_init(); -+ bsp::console::qemu_bring_up_console(); ++ bsp::driver::driver_manager().qemu_bring_up_console(); + + nested_1(); + diff --git a/18_backtrace/kernel/src/_arch/aarch64/exception.rs b/18_backtrace/kernel/src/_arch/aarch64/exception.rs index 30090644..17ec3009 100644 --- a/18_backtrace/kernel/src/_arch/aarch64/exception.rs +++ b/18_backtrace/kernel/src/_arch/aarch64/exception.rs @@ -11,7 +11,7 @@ //! //! crate::exception::arch_exception -use crate::{bsp, exception, memory, symbols}; +use crate::{exception, memory, symbols}; use core::{arch::global_asm, cell::UnsafeCell, fmt}; use cortex_a::{asm::barrier, registers::*}; use tock_registers::{ @@ -108,10 +108,8 @@ unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { #[no_mangle] unsafe extern "C" fn current_elx_irq(_e: &mut ExceptionContext) { - use exception::asynchronous::interface::IRQManager; - let token = &exception::asynchronous::IRQContext::new(); - bsp::exception::asynchronous::irq_manager().handle_pending_irqs(token); + exception::asynchronous::irq_manager().handle_pending_irqs(token); } #[no_mangle] diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs index 4c68a692..e72fde7b 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs @@ -79,8 +79,12 @@ mod gicc; mod gicd; -use crate::{bsp, cpu, driver, exception, memory, synchronization, synchronization::InitStateLock}; -use core::sync::atomic::{AtomicBool, Ordering}; +use crate::{ + bsp, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::InitStateLock, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -97,20 +101,17 @@ pub type IRQNumber = exception::asynchronous::IRQNumber<{ GICv2::MAX_IRQ_NUMBER /// Representation of the GIC. pub struct GICv2 { - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, - /// The Distributor. gicd: gicd::GICD, /// The CPU Interface. gicc: gicc::GICC, - /// Have the MMIO regions been remapped yet? - is_mmio_remapped: AtomicBool, - /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, + + /// Callback to be invoked after successful init. + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -121,22 +122,23 @@ impl GICv2 { const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - gicd_mmio_descriptor: memory::mmu::MMIODescriptor, - gicc_mmio_descriptor: memory::mmu::MMIODescriptor, + gicd_mmio_start_addr: Address, + gicc_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - gicd_mmio_descriptor, - gicc_mmio_descriptor, - gicd: gicd::GICD::new(gicd_mmio_descriptor.start_addr().as_usize()), - gicc: gicc::GICC::new(gicc_mmio_descriptor.start_addr().as_usize()), - is_mmio_remapped: AtomicBool::new(false), + gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr), handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + post_init_callback, } } } @@ -148,24 +150,10 @@ use synchronization::interface::ReadWriteEx; impl driver::interface::DeviceDriver for GICv2 { fn compatible(&self) -> &'static str { - "GICv2 (ARM Generic Interrupt Controller v2)" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let remapped = self.is_mmio_remapped.load(Ordering::Relaxed); - if !remapped { - // GICD - let mut virt_addr = memory::mmu::kernel_map_mmio("GICD", &self.gicd_mmio_descriptor)?; - self.gicd.set_mmio(virt_addr.as_usize()); - - // GICC - virt_addr = memory::mmu::kernel_map_mmio("GICC", &self.gicc_mmio_descriptor)?; - self.gicc.set_mmio(virt_addr.as_usize()); - - // Conclude remapping. - self.is_mmio_remapped.store(true, Ordering::Relaxed); - } - if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { self.gicd.boot_core_init(); } @@ -173,6 +161,8 @@ impl driver::interface::DeviceDriver for GICv2 { self.gicc.priority_accept_all(); self.gicc.enable(); + (self.post_init_callback)(); + Ok(()) } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs index 1a151d24..1a02fc65 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicc.rs @@ -5,7 +5,9 @@ //! GICC Driver - GIC CPU interface. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, exception, synchronization::InitStateLock, + bsp::device_driver::common::MMIODerefWrapper, + exception, + memory::{Address, Virtual}, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -62,13 +64,12 @@ type Registers = MMIODerefWrapper; /// Representation of the GIC CPU interface. pub struct GICC { - registers: InitStateLock, + registers: Registers, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; impl GICC { /// Create an instance. @@ -76,17 +77,12 @@ impl GICC { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - registers: InitStateLock::new(Registers::new(mmio_start_addr)), + registers: Registers::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.registers - .write(|regs| *regs = Registers::new(new_mmio_start_addr)); - } - /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: @@ -99,9 +95,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { - self.registers.read(|regs| { - regs.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. - }); + self.registers.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. @@ -111,9 +105,7 @@ impl GICC { /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { - self.registers.read(|regs| { - regs.CTLR.write(CTLR::Enable::SET); - }); + self.registers.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. @@ -129,8 +121,7 @@ impl GICC { &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { - self.registers - .read(|regs| regs.IAR.read(IAR::InterruptID) as usize) + self.registers.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. @@ -149,8 +140,6 @@ impl GICC { irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { - self.registers.read(|regs| { - regs.EOIR.write(EOIR::EOIINTID.val(irq_number)); - }); + self.registers.EOIR.write(EOIR::EOIINTID.val(irq_number)); } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs index 60bbc468..d9f63d1b 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs @@ -9,8 +9,9 @@ use crate::{ bsp::device_driver::common::MMIODerefWrapper, + memory::{Address, Virtual}, state, synchronization, - synchronization::{IRQSafeNullLock, InitStateLock}, + synchronization::IRQSafeNullLock, }; use tock_registers::{ interfaces::{Readable, Writeable}, @@ -84,7 +85,7 @@ pub struct GICD { shared_registers: IRQSafeNullLock, /// Access to banked registers is unguarded. - banked_registers: InitStateLock, + banked_registers: BankedRegisters, } //-------------------------------------------------------------------------------------------------- @@ -121,7 +122,6 @@ impl SharedRegisters { //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -use crate::synchronization::interface::ReadWriteEx; use synchronization::interface::Mutex; impl GICD { @@ -130,20 +130,13 @@ impl GICD { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { shared_registers: IRQSafeNullLock::new(SharedRegisters::new(mmio_start_addr)), - banked_registers: InitStateLock::new(BankedRegisters::new(mmio_start_addr)), + banked_registers: BankedRegisters::new(mmio_start_addr), } } - pub unsafe fn set_mmio(&self, new_mmio_start_addr: usize) { - self.shared_registers - .lock(|regs| *regs = SharedRegisters::new(new_mmio_start_addr)); - self.banked_registers - .write(|regs| *regs = BankedRegisters::new(new_mmio_start_addr)); - } - /// Use a banked ITARGETSR to retrieve the executing core's GIC target mask. /// /// Quoting the GICv2 Architecture Specification: @@ -151,8 +144,7 @@ impl GICD { /// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each field returns a value that /// corresponds only to the processor reading the register." fn local_gic_target_mask(&self) -> u32 { - self.banked_registers - .read(|regs| regs.ITARGETSR[0].read(ITARGETSR::Offset0)) + self.banked_registers.ITARGETSR[0].read(ITARGETSR::Offset0) } /// Route all SPIs to the boot core and enable the distributor. @@ -191,10 +183,10 @@ impl GICD { // Check if we are handling a private or shared IRQ. match irq_num { // Private. - 0..=31 => self.banked_registers.read(|regs| { - let enable_reg = ®s.ISENABLER; + 0..=31 => { + let enable_reg = &self.banked_registers.ISENABLER; enable_reg.set(enable_reg.get() | enable_bit); - }), + } // Shared. _ => { let enable_reg_index_shared = enable_reg_index - 1; diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index eea07b75..a3361c2c 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -5,10 +5,12 @@ //! GPIO Driver. use crate::{ - bsp::device_driver::common::MMIODerefWrapper, driver, memory, synchronization, + bsp::device_driver::common::MMIODerefWrapper, + driver, + memory::{Address, Virtual}, + synchronization, synchronization::IRQSafeNullLock, }; -use core::sync::atomic::{AtomicUsize, Ordering}; use tock_registers::{ interfaces::{ReadWriteable, Writeable}, register_bitfields, register_structs, @@ -109,26 +111,22 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -137,25 +135,12 @@ impl GPIOInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), } } - /// Init code. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - - Ok(()) - } - /// Disable pull-up/down on pins 14 and 15. #[cfg(feature = "bsp_rpi3")] fn disable_pud_14_15_bcm2837(&mut self) { @@ -205,17 +190,22 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address, post_init_callback: fn()) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(GPIOInner::new(mmio_descriptor.start_addr().as_usize())), + inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)), + post_init_callback, } } @@ -232,28 +222,12 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + (self.post_init_callback)(); Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs index 99961fac..4908b8b6 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs @@ -6,7 +6,10 @@ mod peripheral_ic; -use crate::{driver, exception, memory}; +use crate::{ + driver, exception, + memory::{Address, Virtual}, +}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -28,6 +31,7 @@ pub type PeripheralIRQ = /// Used for the associated type of trait [`exception::asynchronous::interface::IRQManager`]. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub enum IRQNumber { Local(LocalIRQ), Peripheral(PeripheralIRQ), @@ -36,6 +40,7 @@ pub enum IRQNumber { /// Representation of the Interrupt Controller. pub struct InterruptController { periph: peripheral_ic::PeripheralIC, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- @@ -74,17 +79,20 @@ impl InterruptController { const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. pub const unsafe fn new( - _local_mmio_descriptor: memory::mmu::MMIODescriptor, - periph_mmio_descriptor: memory::mmu::MMIODescriptor, + periph_mmio_start_addr: Address, + post_init_callback: fn(), ) -> Self { Self { - periph: peripheral_ic::PeripheralIC::new(periph_mmio_descriptor), + periph: peripheral_ic::PeripheralIC::new(periph_mmio_start_addr), + post_init_callback, } } } @@ -95,11 +103,13 @@ impl InterruptController { impl driver::interface::DeviceDriver for InterruptController { fn compatible(&self) -> &'static str { - "BCM Interrupt Controller" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - self.periph.init() + (self.post_init_callback)(); + + Ok(()) } } diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs index f09da862..145d8961 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs @@ -7,7 +7,9 @@ use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use crate::{ bsp::device_driver::common::MMIODerefWrapper, - driver, exception, memory, synchronization, + exception, + memory::{Address, Virtual}, + synchronization, synchronization::{IRQSafeNullLock, InitStateLock}, }; use tock_registers::{ @@ -55,13 +57,11 @@ type HandlerTable = /// Representation of the peripheral interrupt controller. pub struct PeripheralIC { - mmio_descriptor: memory::mmu::MMIODescriptor, - /// Access to write registers is guarded with a lock. wo_registers: IRQSafeNullLock, /// Register read access is unguarded. - ro_registers: InitStateLock, + ro_registers: ReadOnlyRegisters, /// Stores registered IRQ handlers. Writable only during kernel init. RO afterwards. handler_table: InitStateLock, @@ -76,26 +76,21 @@ impl PeripheralIC { /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. - pub const unsafe fn new(mmio_descriptor: memory::mmu::MMIODescriptor) -> Self { - let addr = mmio_descriptor.start_addr().as_usize(); - + /// - The user must ensure to provide a correct MMIO start address. + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { - mmio_descriptor, - wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(addr)), - ro_registers: InitStateLock::new(ReadOnlyRegisters::new(addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr), handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), } } /// Query the list of pending IRQs. fn pending_irqs(&self) -> PendingIRQs { - self.ro_registers.read(|regs| { - let pending_mask: u64 = - (u64::from(regs.PENDING_2.get()) << 32) | u64::from(regs.PENDING_1.get()); + let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) + | u64::from(self.ro_registers.PENDING_1.get()); - PendingIRQs::new(pending_mask) - }) + PendingIRQs::new(pending_mask) } } @@ -104,24 +99,6 @@ impl PeripheralIC { //------------------------------------------------------------------------------ use synchronization::interface::{Mutex, ReadWriteEx}; -impl driver::interface::DeviceDriver for PeripheralIC { - fn compatible(&self) -> &'static str { - "BCM Peripheral Interrupt Controller" - } - - unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = - memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?.as_usize(); - - self.wo_registers - .lock(|regs| *regs = WriteOnlyRegisters::new(virt_addr)); - self.ro_registers - .write(|regs| *regs = ReadOnlyRegisters::new(virt_addr)); - - Ok(()) - } -} - impl exception::asynchronous::interface::IRQManager for PeripheralIC { type IRQNumberType = PeripheralIRQ; diff --git a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 3133047b..f67d70df 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -10,13 +10,14 @@ //! - use crate::{ - bsp, bsp::device_driver::common::MMIODerefWrapper, console, cpu, driver, exception, memory, - synchronization, synchronization::IRQSafeNullLock, -}; -use core::{ - fmt, - sync::atomic::{AtomicUsize, Ordering}, + bsp, + bsp::device_driver::common::MMIODerefWrapper, + console, cpu, driver, exception, + memory::{Address, Virtual}, + synchronization, + synchronization::IRQSafeNullLock, }; +use core::fmt; use tock_registers::{ interfaces::{Readable, Writeable}, register_bitfields, register_structs, @@ -219,29 +220,25 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { - mmio_descriptor: memory::mmu::MMIODescriptor, - virt_mmio_start_addr: AtomicUsize, inner: IRQSafeNullLock, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -250,7 +247,7 @@ impl PL011UartInner { /// # Safety /// /// - The user must ensure to provide a correct MMIO start address. - pub const unsafe fn new(mmio_start_addr: usize) -> Self { + pub const unsafe fn new(mmio_start_addr: Address) -> Self { Self { registers: Registers::new(mmio_start_addr), chars_written: 0, @@ -275,15 +272,7 @@ impl PL011UartInner { /// genrated baud rate of `48_000_000 / (16 * 3.25) = 923_077`. /// /// Error = `((923_077 - 921_600) / 921_600) * 100 = 0.16%`. - /// - /// # Safety - /// - /// - The user must ensure to provide a correct MMIO start address. - pub unsafe fn init(&mut self, new_mmio_start_addr: Option) -> Result<(), &'static str> { - if let Some(addr) = new_mmio_start_addr { - self.registers = Registers::new(addr); - } - + pub fn init(&mut self) { // Execution can arrive here while there are still characters queued in the TX FIFO and // actively being sent out by the UART hardware. If the UART is turned off in this case, // those queued characters would be lost. @@ -325,8 +314,6 @@ impl PL011UartInner { self.registers .CR .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); - - Ok(()) } /// Send a character. @@ -399,24 +386,28 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety /// - /// - The user must ensure to provide correct MMIO descriptors. + /// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide correct IRQ numbers. pub const unsafe fn new( - mmio_descriptor: memory::mmu::MMIODescriptor, + mmio_start_addr: Address, irq_number: bsp::device_driver::IRQNumber, + post_init_callback: fn(), ) -> Self { Self { - mmio_descriptor, - virt_mmio_start_addr: AtomicUsize::new(0), - inner: IRQSafeNullLock::new(PL011UartInner::new( - mmio_descriptor.start_addr().as_usize(), - )), + inner: IRQSafeNullLock::new(PL011UartInner::new(mmio_start_addr)), irq_number, + post_init_callback, } } } @@ -428,27 +419,21 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { - let virt_addr = memory::mmu::kernel_map_mmio(self.compatible(), &self.mmio_descriptor)?; - - self.inner - .lock(|inner| inner.init(Some(virt_addr.as_usize())))?; - - self.virt_mmio_start_addr - .store(virt_addr.as_usize(), Ordering::Relaxed); + self.inner.lock(|inner| inner.init()); + (self.post_init_callback)(); Ok(()) } fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { - use bsp::exception::asynchronous::irq_manager; - use exception::asynchronous::{interface::IRQManager, IRQDescriptor}; + use exception::asynchronous::{irq_manager, IRQDescriptor}; let descriptor = IRQDescriptor { - name: "BCM PL011 UART", + name: Self::COMPATIBLE, handler: self, }; @@ -457,16 +442,6 @@ impl driver::interface::DeviceDriver for PL011Uart { Ok(()) } - - fn virt_mmio_start_addr(&self) -> Option { - let addr = self.virt_mmio_start_addr.load(Ordering::Relaxed); - - if addr == 0 { - return None; - } - - Some(addr) - } } impl console::interface::Write for PL011Uart { @@ -514,6 +489,8 @@ impl console::interface::Statistics for PL011Uart { } } +impl console::interface::All for PL011Uart {} + impl exception::asynchronous::interface::IRQHandler for PL011Uart { fn handle(&self) -> Result<(), &'static str> { self.inner.lock(|inner| { diff --git a/18_backtrace/kernel/src/bsp/device_driver/common.rs b/18_backtrace/kernel/src/bsp/device_driver/common.rs index fd9e988e..69f038d4 100644 --- a/18_backtrace/kernel/src/bsp/device_driver/common.rs +++ b/18_backtrace/kernel/src/bsp/device_driver/common.rs @@ -4,6 +4,7 @@ //! Common device driver code. +use crate::memory::{Address, Virtual}; use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- @@ -11,7 +12,7 @@ use core::{marker::PhantomData, ops}; //-------------------------------------------------------------------------------------------------- pub struct MMIODerefWrapper { - start_addr: usize, + start_addr: Address, phantom: PhantomData T>, } @@ -21,7 +22,7 @@ pub struct MMIODerefWrapper { impl MMIODerefWrapper { /// Create an instance. - pub const unsafe fn new(start_addr: usize) -> Self { + pub const unsafe fn new(start_addr: Address) -> Self { Self { start_addr, phantom: PhantomData, @@ -33,6 +34,6 @@ impl ops::Deref for MMIODerefWrapper { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.start_addr as *const _) } + unsafe { &*(self.start_addr.as_usize() as *const _) } } } diff --git a/18_backtrace/kernel/src/bsp/raspberrypi.rs b/18_backtrace/kernel/src/bsp/raspberrypi.rs index fb9edf88..474419f4 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi.rs @@ -4,46 +4,11 @@ //! Top-level BSP file for the Raspberry Pi 3 and 4. -pub mod console; pub mod cpu; pub mod driver; pub mod exception; pub mod memory; -use super::device_driver; -use crate::memory::mmu::MMIODescriptor; -use memory::map::mmio; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE)) }; - -static PL011_UART: device_driver::PL011Uart = unsafe { - device_driver::PL011Uart::new( - MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE), - exception::asynchronous::irq_map::PL011_UART, - ) -}; - -#[cfg(feature = "bsp_rpi3")] -static INTERRUPT_CONTROLLER: device_driver::InterruptController = unsafe { - device_driver::InterruptController::new( - MMIODescriptor::new(mmio::LOCAL_IC_START, mmio::LOCAL_IC_SIZE), - MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE), - ) -}; - -#[cfg(feature = "bsp_rpi4")] -static INTERRUPT_CONTROLLER: device_driver::GICv2 = unsafe { - device_driver::GICv2::new( - MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE), - MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE), - ) -}; - //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/console.rs b/18_backtrace/kernel/src/bsp/raspberrypi/console.rs deleted file mode 100644 index a0d2e687..00000000 --- a/18_backtrace/kernel/src/bsp/raspberrypi/console.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// -// Copyright (c) 2018-2022 Andre Richter - -//! BSP console facilities. - -use crate::{bsp::device_driver, console, cpu, driver}; -use core::fmt; - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(not(feature = "test_build"))] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - // If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just - // park the CPU core in this case. - let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - - let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr); - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_gpio - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - panic_gpio.map_pl011_uart(); - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::wait_forever()); - - panic_uart -} - -/// Reduced version for test builds. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -#[cfg(feature = "test_build")] -pub unsafe fn panic_console_out() -> impl fmt::Write { - use driver::interface::DeviceDriver; - - let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() { - None => cpu::wait_forever(), - Some(x) => x, - }; - let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr); - - panic_uart - .init(None) - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - - panic_uart -} - -/// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART -} - -//-------------------------------------------------------------------------------------------------- -// Testing -//-------------------------------------------------------------------------------------------------- - -/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps -/// than on real hardware due to QEMU's abstractions. -#[cfg(feature = "test_build")] -pub fn qemu_bring_up_console() { - use driver::interface::DeviceDriver; - - // Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO - // addresses. - unsafe { - super::PL011_UART - .init() - .unwrap_or_else(|_| cpu::qemu_exit_failure()); - } -} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs index 53168752..e1db4a00 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,19 @@ //! BSP driver support. -use crate::driver; +use super::{exception, memory::map::mmio}; +use crate::{ + bsp::device_driver, + console, driver, exception as generic_exception, memory, + memory::mmu::MMIODescriptor, + synchronization::{interface::ReadWriteEx, InitStateLock}, +}; +use core::{ + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub use device_driver::IRQNumber; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -12,21 +24,132 @@ use crate::driver; /// Device Driver Manager type. struct BSPDriverManager { - device_drivers: [&'static (dyn DeviceDriver + Sync); 3], + device_drivers: InitStateLock<[Option<&'static (dyn DeviceDriver + Sync)>; NUM_DRIVERS]>, + init_done: AtomicBool, } +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +/// The number of active drivers provided by this BSP. +pub const NUM_DRIVERS: usize = 3; + //-------------------------------------------------------------------------------------------------- // Global instances //-------------------------------------------------------------------------------------------------- +static mut PL011_UART: MaybeUninit = MaybeUninit::uninit(); +static mut GPIO: MaybeUninit = MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi3")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = + MaybeUninit::uninit(); + +#[cfg(feature = "bsp_rpi4")] +static mut INTERRUPT_CONTROLLER: MaybeUninit = MaybeUninit::uninit(); + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [ - &super::GPIO, - &super::PL011_UART, - &super::INTERRUPT_CONTROLLER, - ], + device_drivers: InitStateLock::new([None; NUM_DRIVERS]), + init_done: AtomicBool::new(false), }; +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl BSPDriverManager { + unsafe fn instantiate_uart(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::PL011_UART_START, mmio::PL011_UART_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::PL011Uart::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn uart_post_init() { + console::register_console(unsafe { PL011_UART.assume_init_ref() }); + } + + PL011_UART.write(device_driver::PL011Uart::new( + virt_addr, + exception::asynchronous::irq_map::PL011_UART, + uart_post_init, + )); + + Ok(()) + } + + unsafe fn instantiate_gpio(&self) -> Result<(), &'static str> { + let mmio_descriptor = MMIODescriptor::new(mmio::GPIO_START, mmio::GPIO_SIZE); + let virt_addr = + memory::mmu::kernel_map_mmio(device_driver::GPIO::COMPATIBLE, &mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn gpio_post_init() { + unsafe { GPIO.assume_init_ref().map_pl011_uart() }; + } + + GPIO.write(device_driver::GPIO::new(virt_addr, gpio_post_init)); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi3")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let periph_mmio_descriptor = + MMIODescriptor::new(mmio::PERIPHERAL_IC_START, mmio::PERIPHERAL_IC_SIZE); + let periph_virt_addr = memory::mmu::kernel_map_mmio( + device_driver::InterruptController::COMPATIBLE, + &periph_mmio_descriptor, + )?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::InterruptController::new( + periph_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + #[cfg(feature = "bsp_rpi4")] + unsafe fn instantiate_interrupt_controller(&self) -> Result<(), &'static str> { + let gicd_mmio_descriptor = MMIODescriptor::new(mmio::GICD_START, mmio::GICD_SIZE); + let gicd_virt_addr = memory::mmu::kernel_map_mmio("GICv2 GICD", &gicd_mmio_descriptor)?; + + let gicc_mmio_descriptor = MMIODescriptor::new(mmio::GICC_START, mmio::GICC_SIZE); + let gicc_virt_addr = memory::mmu::kernel_map_mmio("GICV2 GICC", &gicc_mmio_descriptor)?; + + // This is safe to do, because it is only called from the init'ed instance itself. + fn interrupt_controller_post_init() { + generic_exception::asynchronous::register_irq_manager(unsafe { + INTERRUPT_CONTROLLER.assume_init_ref() + }); + } + + INTERRUPT_CONTROLLER.write(device_driver::GICv2::new( + gicd_virt_addr, + gicc_virt_addr, + interrupt_controller_post_init, + )); + + Ok(()) + } + + unsafe fn register_drivers(&self) { + self.device_drivers.write(|drivers| { + drivers[0] = Some(PL011_UART.assume_init_ref()); + drivers[1] = Some(GPIO.assume_init_ref()); + drivers[2] = Some(INTERRUPT_CONTROLLER.assume_init_ref()); + }); + } +} + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- @@ -42,20 +165,34 @@ pub fn driver_manager() -> &'static impl driver::interface::DriverManager { use driver::interface::DeviceDriver; impl driver::interface::DriverManager for BSPDriverManager { - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[..] - } + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str> { + if self.init_done.load(Ordering::Relaxed) { + return Err("Drivers already instantiated"); + } + + self.instantiate_uart()?; + self.instantiate_gpio()?; + self.instantiate_interrupt_controller()?; - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[0..=1] + self.register_drivers(); + + self.init_done.store(true, Ordering::Relaxed); + Ok(()) } - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] { - &self.device_drivers[2..] + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); NUM_DRIVERS] { + self.device_drivers + .read(|drivers| drivers.map(|drivers| drivers.unwrap())) } - fn post_early_print_device_driver_init(&self) { - // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self) { + use crate::cpu; + + unsafe { + self.instantiate_uart() + .unwrap_or_else(|_| cpu::qemu_exit_failure()); + console::register_console(PL011_UART.assume_init_ref()); + }; } } diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs index dc5ab421..ab20d86d 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/exception/asynchronous.rs @@ -4,7 +4,7 @@ //! BSP asynchronous exception handling. -use crate::{bsp, exception}; +use crate::bsp; //-------------------------------------------------------------------------------------------------- // Public Definitions @@ -23,14 +23,3 @@ pub(in crate::bsp) mod irq_map { pub const PL011_UART: IRQNumber = IRQNumber::new(153); } - -//-------------------------------------------------------------------------------------------------- -// Public Code -//-------------------------------------------------------------------------------------------------- - -/// Return a reference to the IRQ manager. -pub fn irq_manager() -> &'static impl exception::asynchronous::interface::IRQManager< - IRQNumberType = bsp::device_driver::IRQNumber, -> { - &super::super::INTERRUPT_CONTROLLER -} diff --git a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs index 01aa9441..32416e6c 100644 --- a/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs +++ b/18_backtrace/kernel/src/bsp/raspberrypi/memory.rs @@ -113,9 +113,6 @@ pub(super) mod map { pub const PL011_UART_START: Address = Address::new(0x3F20_1000); pub const PL011_UART_SIZE: usize = 0x48; - pub const LOCAL_IC_START: Address = Address::new(0x4000_0000); - pub const LOCAL_IC_SIZE: usize = 0x100; - pub const END: Address = Address::new(0x4001_0000); } diff --git a/18_backtrace/kernel/src/console.rs b/18_backtrace/kernel/src/console.rs index e49e241f..a85bcffe 100644 --- a/18_backtrace/kernel/src/console.rs +++ b/18_backtrace/kernel/src/console.rs @@ -4,6 +4,10 @@ //! System console. +mod null_console; + +use crate::synchronization; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +53,29 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_CONSOLE: InitStateLock<&'static (dyn interface::All + Sync)> = + InitStateLock::new(&null_console::NULL_CONSOLE); + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; + +/// Register a new console. +pub fn register_console(new_console: &'static (dyn interface::All + Sync)) { + CUR_CONSOLE.write(|con| *con = new_console); +} + +/// Return a reference to the currently registered console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + CUR_CONSOLE.read(|con| *con) } diff --git a/18_backtrace/kernel/src/console/null_console.rs b/18_backtrace/kernel/src/console/null_console.rs new file mode 100644 index 00000000..10c3bedc --- /dev/null +++ b/18_backtrace/kernel/src/console/null_console.rs @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null console. + +use super::interface; +use core::fmt; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullConsole; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_CONSOLE: NullConsole = NullConsole {}; + +//-------------------------------------------------------------------------------------------------- +// Private Code +//-------------------------------------------------------------------------------------------------- + +impl interface::Write for NullConsole { + fn write_char(&self, _c: char) {} + + fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result { + fmt::Result::Ok(()) + } + + fn flush(&self) {} +} + +impl interface::Read for NullConsole { + fn clear_rx(&self) {} +} + +impl interface::Statistics for NullConsole {} +impl interface::All for NullConsole {} diff --git a/18_backtrace/kernel/src/driver.rs b/18_backtrace/kernel/src/driver.rs index 7b800dbc..98197fef 100644 --- a/18_backtrace/kernel/src/driver.rs +++ b/18_backtrace/kernel/src/driver.rs @@ -10,6 +10,8 @@ /// Driver interfaces. pub mod interface { + use crate::bsp; + /// Device Driver functions. pub trait DeviceDriver { /// Return a compatibility string for identifying the driver. @@ -31,32 +33,25 @@ pub mod interface { fn register_and_enable_irq_handler(&'static self) -> Result<(), &'static str> { Ok(()) } - - /// After MMIO remapping, returns the new virtual start address. - /// - /// This API assumes a driver has only a single, contiguous MMIO aperture, which will not be - /// the case for more complex devices. This API will likely change in future tutorials. - fn virt_mmio_start_addr(&self) -> Option { - None - } } /// Device driver management functions. /// /// The `BSP` is supposed to supply one global instance. pub trait DriverManager { - /// Return a slice of references to all `BSP`-instantiated drivers. - fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; - - /// Return only those drivers needed for the BSP's early printing functionality. + /// Instantiate all drivers. + /// + /// # Safety /// - /// For example, the default UART. - fn early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Must be called before `all_device_drivers`. + unsafe fn instantiate_drivers(&self) -> Result<(), &'static str>; - /// Return all drivers minus early-print drivers. - fn non_early_print_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)]; + /// Return a slice of references to all `BSP`-instantiated drivers. + fn all_device_drivers(&self) -> [&(dyn DeviceDriver + Sync); bsp::driver::NUM_DRIVERS]; - /// Initialization code that runs after the early print driver init. - fn post_early_print_device_driver_init(&self); + /// Minimal code needed to bring up the console in QEMU (for testing only). This is often + /// less steps than on real hardware due to QEMU's abstractions. + #[cfg(feature = "test_build")] + fn qemu_bring_up_console(&self); } } diff --git a/18_backtrace/kernel/src/exception/asynchronous.rs b/18_backtrace/kernel/src/exception/asynchronous.rs index fb1785c2..d9d2767c 100644 --- a/18_backtrace/kernel/src/exception/asynchronous.rs +++ b/18_backtrace/kernel/src/exception/asynchronous.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "aarch64")] #[path = "../_arch/aarch64/exception/asynchronous.rs"] mod arch_asynchronous; +mod null_irq_manager; +use crate::{bsp, synchronization}; use core::{fmt, marker::PhantomData}; //-------------------------------------------------------------------------------------------------- @@ -85,7 +87,7 @@ pub mod interface { ); /// Print list of registered handlers. - fn print_handler(&self); + fn print_handler(&self) {} } } @@ -93,9 +95,18 @@ pub mod interface { #[derive(Copy, Clone)] pub struct IRQNumber(usize); +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +static CUR_IRQ_MANAGER: InitStateLock< + &'static (dyn interface::IRQManager + Sync), +> = InitStateLock::new(&null_irq_manager::NULL_IRQ_MANAGER); + //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- +use synchronization::{interface::ReadWriteEx, InitStateLock}; impl<'irq_context> IRQContext<'irq_context> { /// Creates an IRQContext token. @@ -150,3 +161,18 @@ pub fn exec_with_irq_masked(f: impl FnOnce() -> T) -> T { ret } + +/// Register a new IRQ manager. +pub fn register_irq_manager( + new_manager: &'static (dyn interface::IRQManager + + Sync), +) { + CUR_IRQ_MANAGER.write(|manager| *manager = new_manager); +} + +/// Return a reference to the currently registered IRQ manager. +/// +/// This is the IRQ manager used by the architectural interrupt handling code. +pub fn irq_manager() -> &'static dyn interface::IRQManager { + CUR_IRQ_MANAGER.read(|manager| *manager) +} diff --git a/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs new file mode 100644 index 00000000..560e3ce4 --- /dev/null +++ b/18_backtrace/kernel/src/exception/asynchronous/null_irq_manager.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2022 Andre Richter + +//! Null IRQ Manager. + +use super::{interface, IRQContext, IRQDescriptor}; +use crate::bsp; + +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- + +pub struct NullIRQManager; + +//-------------------------------------------------------------------------------------------------- +// Global instances +//-------------------------------------------------------------------------------------------------- + +pub static NULL_IRQ_MANAGER: NullIRQManager = NullIRQManager {}; + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +impl interface::IRQManager for NullIRQManager { + type IRQNumberType = bsp::driver::IRQNumber; + + fn register_handler( + &self, + _irq_number: Self::IRQNumberType, + _descriptor: IRQDescriptor, + ) -> Result<(), &'static str> { + panic!("No IRQ Manager registered yet"); + } + + fn enable(&self, _irq_number: Self::IRQNumberType) { + panic!("No IRQ Manager registered yet"); + } + + fn handle_pending_irqs<'irq_context>(&'irq_context self, _ic: &IRQContext<'irq_context>) { + panic!("No IRQ Manager registered yet"); + } +} diff --git a/18_backtrace/kernel/src/lib.rs b/18_backtrace/kernel/src/lib.rs index 4d7a5f5d..688fc1a4 100644 --- a/18_backtrace/kernel/src/lib.rs +++ b/18_backtrace/kernel/src/lib.rs @@ -114,6 +114,7 @@ #![feature(core_intrinsics)] #![feature(format_args_nl)] #![feature(generic_const_exprs)] +#![feature(is_sorted)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(step_trait)] @@ -178,9 +179,11 @@ pub fn test_runner(tests: &[&test_types::UnitTest]) { #[cfg(test)] #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); test_main(); diff --git a/18_backtrace/kernel/src/main.rs b/18_backtrace/kernel/src/main.rs index 5150f3af..928f12c2 100644 --- a/18_backtrace/kernel/src/main.rs +++ b/18_backtrace/kernel/src/main.rs @@ -30,26 +30,11 @@ unsafe fn kernel_init() -> ! { exception::handling_init(); memory::mmu::post_enable_init(); - // Add the mapping records for the precomputed entries first, so that they appear on the top of - // the list. - bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); - - // Bring up the drivers needed for printing first. - for i in bsp::driver::driver_manager() - .early_print_device_drivers() - .iter() - { - // Any encountered errors cannot be printed yet, obviously, so just safely park the CPU. - i.init().unwrap_or_else(|_| cpu::wait_forever()); + // Instantiate and init all device drivers. + if let Err(x) = bsp::driver::driver_manager().instantiate_drivers() { + panic!("Error instantiating drivers: {}", x); } - bsp::driver::driver_manager().post_early_print_device_driver_init(); - // Printing available from here on. - - // Now bring up the remaining drivers. - for i in bsp::driver::driver_manager() - .non_early_print_device_drivers() - .iter() - { + for i in bsp::driver::driver_manager().all_device_drivers().iter() { if let Err(x) = i.init() { panic!("Error loading driver: {}: {}", i.compatible(), x); } @@ -62,6 +47,8 @@ unsafe fn kernel_init() -> ! { } } + bsp::memory::mmu::kernel_add_mapping_records_for_precomputed(); + // Unmask interrupts on the boot CPU core. exception::asynchronous::local_irq_unmask(); @@ -75,7 +62,6 @@ unsafe fn kernel_init() -> ! { /// The main function running after the early init. fn kernel_main() -> ! { use driver::interface::DriverManager; - use exception::asynchronous::interface::IRQManager; info!("{}", libkernel::version()); info!("Booting on: {}", bsp::board_name()); @@ -104,7 +90,7 @@ fn kernel_main() -> ! { } info!("Registered IRQ handlers:"); - bsp::exception::asynchronous::irq_manager().print_handler(); + exception::asynchronous::irq_manager().print_handler(); info!("Echoing input now"); cpu::wait_forever(); diff --git a/18_backtrace/kernel/src/memory.rs b/18_backtrace/kernel/src/memory.rs index 5e8cdbce..34c34429 100644 --- a/18_backtrace/kernel/src/memory.rs +++ b/18_backtrace/kernel/src/memory.rs @@ -18,18 +18,18 @@ use core::{ //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. -pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} +pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, diff --git a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs index d171c6e6..7d3a6c60 100644 --- a/18_backtrace/kernel/src/memory/mmu/mapping_record.rs +++ b/18_backtrace/kernel/src/memory/mmu/mapping_record.rs @@ -76,6 +76,19 @@ impl MappingRecord { Self { inner: [None; 12] } } + fn size(&self) -> usize { + self.inner.iter().filter(|x| x.is_some()).count() + } + + fn sort(&mut self) { + let upper_bound_exclusive = self.size(); + let entries = &mut self.inner[0..upper_bound_exclusive]; + + if !entries.is_sorted_by_key(|item| item.unwrap().virt_start_addr) { + entries.sort_unstable_by_key(|item| item.unwrap().virt_start_addr) + } + } + fn find_next_free(&mut self) -> Result<&mut Option, &'static str> { if let Some(x) = self.inner.iter_mut().find(|x| x.is_none()) { return Ok(x); @@ -121,6 +134,9 @@ impl MappingRecord { phys_region, attr, )); + + self.sort(); + Ok(()) } diff --git a/18_backtrace/kernel/src/panic_wait.rs b/18_backtrace/kernel/src/panic_wait.rs index 1b67c533..c8e86fbd 100644 --- a/18_backtrace/kernel/src/panic_wait.rs +++ b/18_backtrace/kernel/src/panic_wait.rs @@ -4,19 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{backtrace, bsp, cpu, exception}; -use core::{fmt, panic::PanicInfo}; +use crate::{backtrace, cpu, exception, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - /// The point of exit for `libkernel`. /// /// It is linked weakly, so that the integration tests can overload its standard behavior. @@ -34,16 +28,6 @@ fn _panic_exit() -> ! { } } -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -88,7 +72,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}\n\n\ diff --git a/18_backtrace/kernel/src/print.rs b/18_backtrace/kernel/src/print.rs index 9ec13a28..8705eec0 100644 --- a/18_backtrace/kernel/src/print.rs +++ b/18_backtrace/kernel/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline. diff --git a/18_backtrace/kernel/tests/00_console_sanity.rs b/18_backtrace/kernel/tests/00_console_sanity.rs index 6595aac1..f2a1f3ed 100644 --- a/18_backtrace/kernel/tests/00_console_sanity.rs +++ b/18_backtrace/kernel/tests/00_console_sanity.rs @@ -11,16 +11,16 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, console, cpu, exception, memory, print}; +use libkernel::{bsp, console, cpu, driver, exception, memory, print}; #[no_mangle] unsafe fn kernel_init() -> ! { - use bsp::console::console; - use console::interface::*; + use console::console; + use driver::interface::DriverManager; exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Handshake assert_eq!(console().read_char(), 'A'); diff --git a/18_backtrace/kernel/tests/01_timer_sanity.rs b/18_backtrace/kernel/tests/01_timer_sanity.rs index 9b2b228d..caeca3cd 100644 --- a/18_backtrace/kernel/tests/01_timer_sanity.rs +++ b/18_backtrace/kernel/tests/01_timer_sanity.rs @@ -11,14 +11,16 @@ #![test_runner(libkernel::test_runner)] use core::time::Duration; -use libkernel::{bsp, cpu, exception, memory, time, time::interface::TimeManager}; +use libkernel::{bsp, cpu, driver, exception, memory, time, time::interface::TimeManager}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // Depending on CPU arch, some timer bring-up code could go here. Not needed for the RPi. diff --git a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs index 0d2a1e63..33463e0a 100644 --- a/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs +++ b/18_backtrace/kernel/tests/02_exception_sync_page_fault.rs @@ -17,13 +17,15 @@ /// or indirectly. mod panic_exit_success; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing synchronous exception handling by causing a page fault"); diff --git a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs index 983d488f..a521a871 100644 --- a/18_backtrace/kernel/tests/03_exception_restore_sanity.rs +++ b/18_backtrace/kernel/tests/03_exception_restore_sanity.rs @@ -12,7 +12,7 @@ mod panic_wait_forever; use core::arch::asm; -use libkernel::{bsp, cpu, exception, info, memory, println}; +use libkernel::{bsp, cpu, driver, exception, info, memory, println}; #[inline(never)] fn nested_system_call() { @@ -30,9 +30,11 @@ fn nested_system_call() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); // This line will be printed as the test header. println!("Testing exception restore"); diff --git a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs index 9030424d..cd2d29d6 100644 --- a/18_backtrace/kernel/tests/04_exception_irq_sanity.rs +++ b/18_backtrace/kernel/tests/04_exception_irq_sanity.rs @@ -10,13 +10,15 @@ #![reexport_test_harness_main = "test_main"] #![test_runner(libkernel::test_runner)] -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; use test_macros::kernel_test; #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); exception::handling_init(); exception::asynchronous::local_irq_unmask(); diff --git a/18_backtrace/kernel/tests/05_backtrace_sanity.rs b/18_backtrace/kernel/tests/05_backtrace_sanity.rs index 24229f95..4475fafd 100644 --- a/18_backtrace/kernel/tests/05_backtrace_sanity.rs +++ b/18_backtrace/kernel/tests/05_backtrace_sanity.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{bsp, cpu, exception, memory}; +use libkernel::{bsp, cpu, driver, exception, memory}; #[inline(never)] fn nested() { @@ -20,9 +20,11 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs index a1874c4e..74dad8d8 100644 --- a/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs +++ b/18_backtrace/kernel/tests/06_backtrace_invalid_frame.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, exception, memory}; +use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; #[inline(never)] fn nested() { @@ -22,9 +22,11 @@ fn nested() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); nested(); diff --git a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs index a0731091..ba6c9f57 100644 --- a/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs +++ b/18_backtrace/kernel/tests/07_backtrace_invalid_link.rs @@ -11,7 +11,7 @@ /// Console tests should time out on the I/O harness in case of panic. mod panic_wait_forever; -use libkernel::{backtrace, bsp, cpu, exception, memory}; +use libkernel::{backtrace, bsp, cpu, driver, exception, memory}; #[inline(never)] fn nested_2() -> &'static str { @@ -27,9 +27,11 @@ fn nested_1() { #[no_mangle] unsafe fn kernel_init() -> ! { + use driver::interface::DriverManager; + exception::handling_init(); memory::mmu::post_enable_init(); - bsp::console::qemu_bring_up_console(); + bsp::driver::driver_manager().qemu_bring_up_console(); nested_1(); diff --git a/X1_JTAG_boot/.vscode/settings.json b/X1_JTAG_boot/.vscode/settings.json index 292bf2a9..d1916456 100644 --- a/X1_JTAG_boot/.vscode/settings.json +++ b/X1_JTAG_boot/.vscode/settings.json @@ -4,7 +4,7 @@ "rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat", "rust-analyzer.cargo.features": ["bsp_rpi3"], "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": ["--lib", "--bins"], + "rust-analyzer.checkOnSave.extraArgs": ["--bins"], "rust-analyzer.lens.debug": false, "rust-analyzer.lens.run": false } diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs index dbb4beaa..24958eb5 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs @@ -108,16 +108,13 @@ register_structs! { /// Abstraction for the associated MMIO registers. type Registers = MMIODerefWrapper; -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct GPIOInner { +struct GPIOInner { registers: Registers, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use GPIOInner as PanicGPIO; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the GPIO HW. pub struct GPIO { @@ -125,7 +122,7 @@ pub struct GPIO { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl GPIOInner { @@ -189,7 +186,13 @@ impl GPIOInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl GPIO { + pub const COMPATIBLE: &'static str = "BCM GPIO"; + /// Create an instance. /// /// # Safety @@ -214,6 +217,6 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for GPIO { fn compatible(&self) -> &'static str { - "BCM GPIO" + Self::COMPATIBLE } } diff --git a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs index 85cd3154..b034e92e 100644 --- a/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs +++ b/X1_JTAG_boot/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs @@ -167,18 +167,15 @@ enum BlockingMode { NonBlocking, } -//-------------------------------------------------------------------------------------------------- -// Public Definitions -//-------------------------------------------------------------------------------------------------- - -pub struct PL011UartInner { +struct PL011UartInner { registers: Registers, chars_written: usize, chars_read: usize, } -// Export the inner struct so that BSPs can use it for the panic handler. -pub use PL011UartInner as PanicUart; +//-------------------------------------------------------------------------------------------------- +// Public Definitions +//-------------------------------------------------------------------------------------------------- /// Representation of the UART. pub struct PL011Uart { @@ -186,7 +183,7 @@ pub struct PL011Uart { } //-------------------------------------------------------------------------------------------------- -// Public Code +// Private Code //-------------------------------------------------------------------------------------------------- impl PL011UartInner { @@ -326,7 +323,13 @@ impl fmt::Write for PL011UartInner { } } +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + impl PL011Uart { + pub const COMPATIBLE: &'static str = "BCM PL011 UART"; + /// Create an instance. /// /// # Safety @@ -346,7 +349,7 @@ use synchronization::interface::Mutex; impl driver::interface::DeviceDriver for PL011Uart { fn compatible(&self) -> &'static str { - "BCM PL011 UART" + Self::COMPATIBLE } unsafe fn init(&self) -> Result<(), &'static str> { @@ -400,3 +403,5 @@ impl console::interface::Statistics for PL011Uart { self.inner.lock(|inner| inner.chars_read) } } + +impl console::interface::All for PL011Uart {} diff --git a/X1_JTAG_boot/src/bsp/raspberrypi.rs b/X1_JTAG_boot/src/bsp/raspberrypi.rs index f8dbc1f4..eb6be81a 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi.rs @@ -8,14 +8,3 @@ pub mod console; pub mod cpu; pub mod driver; pub mod memory; - -//-------------------------------------------------------------------------------------------------- -// Global instances -//-------------------------------------------------------------------------------------------------- -use super::device_driver; - -static GPIO: device_driver::GPIO = - unsafe { device_driver::GPIO::new(memory::map::mmio::GPIO_START) }; - -static PL011_UART: device_driver::PL011Uart = - unsafe { device_driver::PL011Uart::new(memory::map::mmio::PL011_UART_START) }; diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/console.rs b/X1_JTAG_boot/src/bsp/raspberrypi/console.rs index a247032f..0a630eef 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/console.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/console.rs @@ -4,34 +4,13 @@ //! BSP console facilities. -use super::memory; -use crate::{bsp::device_driver, console}; -use core::fmt; +use crate::console; //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- -/// In case of a panic, the panic handler uses this function to take a last shot at printing -/// something before the system is halted. -/// -/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected -/// with synchronization primitives, which increases chances that we get to print something, even -/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic. -/// -/// # Safety -/// -/// - Use only for printing during a panic. -pub unsafe fn panic_console_out() -> impl fmt::Write { - let mut panic_gpio = device_driver::PanicGPIO::new(memory::map::mmio::GPIO_START); - let mut panic_uart = device_driver::PanicUart::new(memory::map::mmio::PL011_UART_START); - - panic_gpio.map_pl011_uart(); - panic_uart.init(); - panic_uart -} - /// Return a reference to the console. -pub fn console() -> &'static impl console::interface::All { - &super::PL011_UART +pub fn console() -> &'static dyn console::interface::All { + &super::driver::PL011_UART } diff --git a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs index b5538baa..8b683ed8 100644 --- a/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs +++ b/X1_JTAG_boot/src/bsp/raspberrypi/driver.rs @@ -4,7 +4,8 @@ //! BSP driver support. -use crate::driver; +use super::memory::map::mmio; +use crate::{bsp::device_driver, driver}; //-------------------------------------------------------------------------------------------------- // Private Definitions @@ -19,8 +20,13 @@ struct BSPDriverManager { // Global instances //-------------------------------------------------------------------------------------------------- +pub(super) static PL011_UART: device_driver::PL011Uart = + unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) }; + +static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) }; + static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager { - device_drivers: [&super::GPIO, &super::PL011_UART], + device_drivers: [&PL011_UART, &GPIO], }; //-------------------------------------------------------------------------------------------------- @@ -44,6 +50,6 @@ impl driver::interface::DriverManager for BSPDriverManager { fn post_device_driver_init(&self) { // Configure PL011Uart's output pins. - super::GPIO.map_pl011_uart(); + GPIO.map_pl011_uart(); } } diff --git a/X1_JTAG_boot/src/console.rs b/X1_JTAG_boot/src/console.rs index e49e241f..c1fb0e53 100644 --- a/X1_JTAG_boot/src/console.rs +++ b/X1_JTAG_boot/src/console.rs @@ -4,6 +4,8 @@ //! System console. +use crate::bsp; + //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- @@ -49,5 +51,16 @@ pub mod interface { } /// Trait alias for a full-fledged console. - pub trait All = Write + Read + Statistics; + pub trait All: Write + Read + Statistics {} +} + +//-------------------------------------------------------------------------------------------------- +// Public Code +//-------------------------------------------------------------------------------------------------- + +/// Return a reference to the console. +/// +/// This is the global console used by all printing macros. +pub fn console() -> &'static dyn interface::All { + bsp::console::console() } diff --git a/X1_JTAG_boot/src/panic_wait.rs b/X1_JTAG_boot/src/panic_wait.rs index f851e0d8..edd83885 100644 --- a/X1_JTAG_boot/src/panic_wait.rs +++ b/X1_JTAG_boot/src/panic_wait.rs @@ -4,29 +4,13 @@ //! A panic handler that infinitely waits. -use crate::{bsp, cpu}; -use core::{fmt, panic::PanicInfo}; +use crate::{cpu, println}; +use core::panic::PanicInfo; //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- -fn _panic_print(args: fmt::Arguments) { - use fmt::Write; - - unsafe { bsp::console::panic_console_out().write_fmt(args).unwrap() }; -} - -/// Prints with a newline - only use from the panic handler. -/// -/// Carbon copy from -#[macro_export] -macro_rules! panic_println { - ($($arg:tt)*) => ({ - _panic_print(format_args_nl!($($arg)*)); - }) -} - /// Stop immediately if called a second time. /// /// # Note @@ -69,7 +53,7 @@ fn panic(info: &PanicInfo) -> ! { _ => ("???", 0, 0), }; - panic_println!( + println!( "[ {:>3}.{:06}] Kernel panic!\n\n\ Panic location:\n File '{}', line {}, column {}\n\n\ {}", diff --git a/X1_JTAG_boot/src/print.rs b/X1_JTAG_boot/src/print.rs index 9ec13a28..8705eec0 100644 --- a/X1_JTAG_boot/src/print.rs +++ b/X1_JTAG_boot/src/print.rs @@ -4,7 +4,7 @@ //! Printing. -use crate::{bsp, console}; +use crate::console; use core::fmt; //-------------------------------------------------------------------------------------------------- @@ -13,9 +13,7 @@ use core::fmt; #[doc(hidden)] pub fn _print(args: fmt::Arguments) { - use console::interface::Write; - - bsp::console::console().write_fmt(args).unwrap(); + console::console().write_fmt(args).unwrap(); } /// Prints without a newline.