Rework driver subsystem

- Remove the panic version of the GPIO and UART driver. While they were a neat
  idea, it proved tedious to drag them along different tutorials where the
  virtual memory situation kept on changing. Actually, not much is lost, since
  the benefit was only of theoretical nature until now, since everything is
  still single-threaded with NullLocks. It is still possible to re-introduce
  them later.

- Refactor driver bringup starting with tutorial 14. Instantiating the drivers
  only when we are already capable of using the remapped MMIO address makes the
  kernel a lot more robust, and the drivers need not care whether their MMIO
  addresses are good to use already or not.

- Use console and irq_manager references from the generic kernel code. This
  improves decoupling from the BSP, and is needed as a basis for tutorial 14.
pull/165/head
Andre Richter 2 years ago
parent 4ab609ba39
commit fec4f9b6f2
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

3
.gitignore vendored

@ -3,7 +3,8 @@
**/kernel8.img
node_modules
.bundle
.vendor
Gemfile.lock
package-lock.json
package*.json

@ -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 <andre.o.richter@gmail.com>
+
+//! 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.

@ -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()
}

@ -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.

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

@ -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 {}

@ -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()
}

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

@ -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.

@ -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 <andre.o.richter@gmail.com>
@ -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<RegisterBlock>;
+
+//--------------------------------------------------------------------------------------------------
+// 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 <andre.o.richter@gmail.com>
@ -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 <andre.o.richter@gmail.com>
+
+//! 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 <https://doc.rust-lang.org/src/std/macros.rs.html>
+#[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

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

@ -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()
}

@ -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);
}
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

@ -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');

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

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

@ -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()
}

@ -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());

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

@ -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)*));
})
}

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

@ -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()
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

@ -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()
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

@ -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);
}
}

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

@ -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()
}

@ -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);
}
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

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

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

@ -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()
}

@ -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);
}
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

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

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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
}

@ -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();
}
}

@ -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()
}

@ -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);
}
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

@ -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');

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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 {}

@ -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
//--------------------------------------------------------------------------------------------------

@ -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() {}

@ -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) {}
}

@ -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()
}

@ -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);
}
}

@ -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();

@ -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);
}
}

@ -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 <https://doc.rust-lang.org/src/std/macros.rs.html>
#[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\
{}",

@ -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.

@ -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');

@ -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.

@ -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");

@ -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");

@ -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 <andre.o.richter@gmail.com>
@ -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 <andre.o.richter@gmail.com>
@ -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<u32, ICR::Register>),
(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<IRQNumberType = bsp::driver::IRQNumber> {
+ 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 <andre.o.richter@gmail.com>
@ -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();

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

@ -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> {

@ -108,16 +108,13 @@ register_structs! {
/// Abstraction for the associated MMIO registers.
type Registers = MMIODerefWrapper<RegisterBlock>;
//--------------------------------------------------------------------------------------------------
// 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
}
}

@ -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
}
}

@ -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| {

@ -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
//--------------------------------------------------------------------------------------------------

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save