Separate init from main

pull/35/head
Andre Richter 5 years ago
parent 16381c4db8
commit 2933bcf162
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

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

@ -10,9 +10,9 @@ We are calling into Rust code for the first time.
- `_start()`:
- Halt core if core != `core0`.
- `core0` jumps to `init()` Rust function.
- `init()`
- `init()` in `runtime.rs`
- Zeros the `.bss` section.
- Calls `kernel_entry()`, which calls `panic!()`, which eventually halts
- Calls `kernel_init()`, which calls `panic!()`, which eventually halts
`core0` as well.
## Diff to previous
@ -50,22 +50,6 @@ diff -uNr 01_wait_forever/src/arch/aarch64/start.S 02_runtime_init/src/arch/aarc
+ b 1b // We should never reach here. But just in case,
+ // park this core aswell
diff -uNr 01_wait_forever/src/arch/aarch64.rs 02_runtime_init/src/arch/aarch64.rs
--- 01_wait_forever/src/arch/aarch64.rs
+++ 02_runtime_init/src/arch/aarch64.rs
@@ -6,9 +6,9 @@
global_asm!(include_str!("aarch64/start.S"));
-////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation of the kernel's architecture abstraction code
-////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
/// Pause execution on the calling CPU core.
#[inline(always)]
diff -uNr 01_wait_forever/src/bsp/rpi3/link.ld 02_runtime_init/src/bsp/rpi3/link.ld
--- 01_wait_forever/src/bsp/rpi3/link.ld
+++ 02_runtime_init/src/bsp/rpi3/link.ld
@ -97,11 +81,11 @@ diff -uNr 01_wait_forever/src/bsp/rpi3/link.ld 02_runtime_init/src/bsp/rpi3/link
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
--- 01_wait_forever/src/main.rs
+++ 02_runtime_init/src/main.rs
@@ -16,9 +16,15 @@
@@ -16,9 +16,19 @@
// the first function to run.
mod arch;
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
+mod runtime_init;
+
// Conditionally includes the selected `BSP` code.
@ -110,25 +94,27 @@ diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
mod panic_wait;
-// Kernel code coming next tutorial.
+/// Entrypoint of the `kernel`.
+fn kernel_entry() -> ! {
+/// Early init code.
+///
+/// # Safety
+///
+/// - Only a single core must be active and running this function.
+unsafe fn kernel_init() -> ! {
+ panic!()
+}
diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.rs
--- 01_wait_forever/src/runtime_init.rs
+++ 02_runtime_init/src/runtime_init.rs
@@ -0,0 +1,27 @@
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
+
+//! Rust runtime initialization code.
+
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
+/// kernel entry.
+///
+/// Called from `BSP` code.
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
+/// init code.
+///
+/// # Safety
+///
@ -144,6 +130,6 @@ diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.r
+ // Zero out the .bss section.
+ r0::zero_bss(&mut __bss_start, &mut __bss_end);
+
+ crate::kernel_entry()
+ crate::kernel_init()
+}
```

Binary file not shown.

Binary file not shown.

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

@ -16,7 +16,7 @@
// the first function to run.
mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@ -24,7 +24,11 @@ mod bsp;
mod panic_wait;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
/// Early init code.
///
/// # Safety
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
panic!()
}

@ -4,10 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
/// init code.
///
/// # Safety
///
@ -23,5 +21,5 @@ pub unsafe extern "C" fn init() -> ! {
// Zero out the .bss section.
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
crate::kernel_init()
}

@ -8,7 +8,7 @@ QEMU property and doesn't really use the RPi3's `UART`; Using real `UART` is
enabled step-by-step in following tutorials.
- `interface.rs` is introduced:
- Provides `Traits` for abstracting `kernel` from `BSP` code.
- Provides `Traits` for abstracting `kernel` from `BSP` and `arch` code.
- Panic handler `print!()`s supplied error messages.
- This is showcased in `main()`.
@ -28,22 +28,6 @@ diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
endif
diff -uNr 02_runtime_init/src/arch/aarch64.rs 03_hacky_hello_world/src/arch/aarch64.rs
--- 02_runtime_init/src/arch/aarch64.rs
+++ 03_hacky_hello_world/src/arch/aarch64.rs
@@ -6,9 +6,9 @@
global_asm!(include_str!("aarch64/start.S"));
-////////////////////////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
// Implementation of the kernel's architecture abstraction code
-////////////////////////////////////////////////////////////////////////////////////////////////////
+//--------------------------------------------------------------------------------------------------
/// Pause execution on the calling CPU core.
#[inline(always)]
diff -uNr 02_runtime_init/src/bsp/rpi3.rs 03_hacky_hello_world/src/bsp/rpi3.rs
--- 02_runtime_init/src/bsp/rpi3.rs
+++ 03_hacky_hello_world/src/bsp/rpi3.rs
@ -153,15 +137,7 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
#![no_main]
#![no_std]
@@ -16,15 +30,20 @@
// the first function to run.
mod arch;
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to
+// `kernel_entry()`.
mod runtime_init;
@@ -22,7 +36,9 @@
// Conditionally includes the selected `BSP` code.
mod bsp;
@ -169,8 +145,12 @@ diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
mod panic_wait;
+mod print;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
/// Early init code.
///
@@ -30,5 +46,7 @@
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
- panic!()
+ println!("Hello from Rust!");
+

Binary file not shown.

Binary file not shown.

@ -30,8 +30,7 @@
// the first function to run.
mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to
// `kernel_entry()`.
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@ -41,8 +40,12 @@ mod interface;
mod panic_wait;
mod print;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
/// Early init code.
///
/// # Safety
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
println!("Hello from Rust!");
panic!("Stopping here.")

@ -4,10 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
/// init code.
///
/// # Safety
///
@ -23,5 +21,5 @@ pub unsafe extern "C" fn init() -> ! {
// Zero out the .bss section.
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
crate::kernel_init()
}

@ -125,10 +125,10 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main
#![feature(panic_info_message)]
#![no_main]
#![no_std]
@@ -43,7 +41,8 @@
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
@@ -46,7 +44,8 @@
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
- println!("Hello from Rust!");
+ println!("[0] Hello from pure Rust!");
@ -140,7 +140,7 @@ diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main
diff -uNr 03_hacky_hello_world/src/runtime_init.rs 04_zero_overhead_abstraction/src/runtime_init.rs
--- 03_hacky_hello_world/src/runtime_init.rs
+++ 04_zero_overhead_abstraction/src/runtime_init.rs
@@ -12,8 +12,7 @@
@@ -10,8 +10,7 @@
/// # Safety
///
/// - Only a single core must be active and running this function.

@ -28,8 +28,7 @@
// the first function to run.
mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to
// `kernel_entry()`.
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@ -39,8 +38,12 @@ mod interface;
mod panic_wait;
mod print;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
/// Early init code.
///
/// # Safety
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
println!("[0] Hello from pure Rust!");
println!("[1] Stopping here.");

@ -4,10 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
/// init code.
///
/// # Safety
///
@ -22,5 +20,5 @@ pub unsafe fn init() -> ! {
// Zero out the .bss section.
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
crate::kernel_init()
}

@ -322,20 +322,10 @@ diff -uNr 04_zero_overhead_abstraction/src/main.rs 05_safe_globals/src/main.rs
#![no_main]
#![no_std]
@@ -28,8 +29,7 @@
// the first function to run.
mod arch;
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to
-// `kernel_entry()`.
+// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@@ -41,8 +41,12 @@
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
@@ -44,8 +45,12 @@
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
+ use interface::console::Statistics;
+
println!("[0] Hello from pure Rust!");

Binary file not shown.

@ -29,7 +29,7 @@
// the first function to run.
mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@ -39,8 +39,12 @@ mod interface;
mod panic_wait;
mod print;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
/// Early init code.
///
/// # Safety
///
/// - Only a single core must be active and running this function.
unsafe fn kernel_init() -> ! {
use interface::console::Statistics;
println!("[0] Hello from pure Rust!");

@ -4,10 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
/// init code.
///
/// # Safety
///
@ -22,5 +20,5 @@ pub unsafe fn init() -> ! {
// Zero out the .bss section.
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
crate::kernel_init()
}

@ -4,7 +4,7 @@
Now that we enabled safe globals in the previous tutorial, the infrastructure is
laid for adding the first real device drivers. We throw out the magic QEMU
console and use a real UART now. Like real tough embedded people do!
console and use a real UART now. Like serious embedded hackers do!
- A `DeviceDriver` trait is added for abstracting `BSP` driver implementations
from kernel code.
@ -55,11 +55,18 @@ diff -uNr 05_safe_globals/Cargo.toml 06_drivers_gpio_uart/Cargo.toml
diff -uNr 05_safe_globals/src/arch/aarch64.rs 06_drivers_gpio_uart/src/arch/aarch64.rs
--- 05_safe_globals/src/arch/aarch64.rs
+++ 06_drivers_gpio_uart/src/arch/aarch64.rs
@@ -33,6 +33,8 @@
@@ -33,6 +33,15 @@
// Implementation of the kernel's architecture abstraction code
//--------------------------------------------------------------------------------------------------
+pub use asm::nop;
+
+/// Spin for `n` cycles.
+pub fn spin_for_cycles(n: usize) {
+ for _ in 0..n {
+ asm::nop();
+ }
+}
+
/// Pause execution on the calling CPU core.
#[inline(always)]
@ -68,7 +75,7 @@ diff -uNr 05_safe_globals/src/arch/aarch64.rs 06_drivers_gpio_uart/src/arch/aarc
diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2837_gpio.rs 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2837_gpio.rs
--- 05_safe_globals/src/bsp/driver/bcm/bcm2837_gpio.rs
+++ 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2837_gpio.rs
@@ -0,0 +1,162 @@
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
@ -184,15 +191,11 @@ diff -uNr 05_safe_globals/src/bsp/driver/bcm/bcm2837_gpio.rs 06_drivers_gpio_uar
+
+ // Enable pins 14 and 15.
+ self.GPPUD.set(0);
+ for _ in 0..150 {
+ arch::nop();
+ }
+ arch::spin_for_cycles(150);
+
+ self.GPPUDCLK0
+ .write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
+ for _ in 0..150 {
+ arch::nop();
+ }
+ arch::spin_for_cycles(150);
+
+ self.GPPUDCLK0.set(0);
+ }
@ -575,7 +578,7 @@ diff -uNr 05_safe_globals/src/bsp/rpi3/memory_map.rs 06_drivers_gpio_uart/src/bs
diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
--- 05_safe_globals/src/bsp/rpi3.rs
+++ 06_drivers_gpio_uart/src/bsp/rpi3.rs
@@ -4,114 +4,58 @@
@@ -4,114 +4,47 @@
//! Board Support Package for the Raspberry Pi 3.
@ -697,8 +700,11 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
-//--------------------------------------------------------------------------------------------------
-
-static QEMU_OUTPUT: QEMUOutput = QEMUOutput::new();
+/// Return an array of references to all `DeviceDriver` compatible `BSP`
+/// drivers.
-
-//--------------------------------------------------------------------------------------------------
-// Implementation of the kernel's BSP calls
-//--------------------------------------------------------------------------------------------------
+/// Return an array of references to all `DeviceDriver` compatible `BSP` drivers.
+///
+/// # Safety
+///
@ -707,24 +713,11 @@ diff -uNr 05_safe_globals/src/bsp/rpi3.rs 06_drivers_gpio_uart/src/bsp/rpi3.rs
+ [&GPIO, &MINI_UART]
+}
-//--------------------------------------------------------------------------------------------------
-// Implementation of the kernel's BSP calls
-//--------------------------------------------------------------------------------------------------
+/// The BSP's main initialization function.
+///
+/// Called early on kernel start.
+pub fn init() {
+ for i in device_drivers().iter() {
+ if let Err(()) = i.init() {
+ // This message will only be readable if, at the time of failure, the return value of
+ // `bsp::console()` is already in functioning state.
+ panic!("Error loading driver: {}", i.compatible())
+ }
+ }
-/// Return a reference to a `console::All` implementation.
-pub fn console() -> &'static impl interface::console::All {
- &QEMU_OUTPUT
+/// BSP initialization code that runs after driver init.
+pub fn post_driver_init() {
+ // Configure MiniUart's output pins.
+ GPIO.map_mini_uart();
}
@ -763,7 +756,7 @@ diff -uNr 05_safe_globals/src/interface.rs 06_drivers_gpio_uart/src/interface.rs
+ /// Driver result type, e.g. for indicating successful driver init.
+ pub type Result = core::result::Result<(), ()>;
+
+ /// Device Driver operations.
+ /// Device Driver functions.
+ pub trait DeviceDriver {
+ /// Return a compatibility string for identifying the driver.
+ fn compatible(&self) -> &str;
@ -778,30 +771,58 @@ diff -uNr 05_safe_globals/src/interface.rs 06_drivers_gpio_uart/src/interface.rs
diff -uNr 05_safe_globals/src/main.rs 06_drivers_gpio_uart/src/main.rs
--- 05_safe_globals/src/main.rs
+++ 06_drivers_gpio_uart/src/main.rs
@@ -41,12 +41,23 @@
@@ -41,16 +41,50 @@
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
/// Early init code.
///
+/// Concerned with with initializing `BSP` and `arch` parts.
+///
/// # 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 interface::console::Statistics;
+ for i in bsp::device_drivers().iter() {
+ if let Err(()) = i.init() {
+ // This message will only be readable if, at the time of failure, the return value of
+ // `bsp::console()` is already in functioning state.
+ panic!("Error loading driver: {}", i.compatible())
+ }
+ }
+
+ bsp::post_driver_init();
+
+ // Transition from unsafe to safe.
+ kernel_main()
+}
+
+/// The main function running after the early init.
+fn kernel_main() -> ! {
+ use interface::console::All;
- println!("[0] Hello from pure Rust!");
+ // Run the BSP's initialization code.
+ bsp::init();
- println!("[1] Chars written: {}", bsp::console().chars_written());
+
+ // UART should be functional now. Wait for user to hit Enter.
+ loop {
+ if bsp::console().read_char() == '
' {
+ break;
+ }
+ }
+
+ println!("[0] Booting on: {}", bsp::board_name());
- println!("[2] Stopping here.");
- arch::wait_forever()
- println!("[0] Hello from pure Rust!");
+ println!("[1] Drivers loaded:");
+ for (i, driver) in bsp::device_drivers().iter().enumerate() {
+ println!(" {}. {}", i + 1, driver.compatible());
+ }
+
- println!("[1] Chars written: {}", bsp::console().chars_written());
+ println!("[2] Chars written: {}", bsp::console().chars_written());
+ println!("[3] Echoing input now");
+
- println!("[2] Stopping here.");
- arch::wait_forever()
+ loop {
+ let c = bsp::console().read_char();
+ bsp::console().write_char(c);

Binary file not shown.

Binary file not shown.

@ -35,6 +35,13 @@ pub unsafe extern "C" fn _start() -> ! {
pub use asm::nop;
/// Spin for `n` cycles.
pub fn spin_for_cycles(n: usize) {
for _ in 0..n {
asm::nop();
}
}
/// Pause execution on the calling CPU core.
#[inline(always)]
pub fn wait_forever() -> ! {

@ -113,15 +113,11 @@ impl GPIOInner {
// Enable pins 14 and 15.
self.GPPUD.set(0);
for _ in 0..150 {
arch::nop();
}
arch::spin_for_cycles(150);
self.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
for _ in 0..150 {
arch::nop();
}
arch::spin_for_cycles(150);
self.GPPUDCLK0.set(0);
}

@ -43,18 +43,8 @@ pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
[&GPIO, &MINI_UART]
}
/// The BSP's main initialization function.
///
/// Called early on kernel start.
pub fn init() {
for i in device_drivers().iter() {
if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure, the return value of
// `bsp::console()` is already in functioning state.
panic!("Error loading driver: {}", i.compatible())
}
}
/// BSP initialization code that runs after driver init.
pub fn post_driver_init() {
// Configure MiniUart's output pins.
GPIO.map_mini_uart();
}

@ -90,7 +90,7 @@ pub mod driver {
/// Driver result type, e.g. for indicating successful driver init.
pub type Result = core::result::Result<(), ()>;
/// Device Driver operations.
/// Device Driver functions.
pub trait DeviceDriver {
/// Return a compatibility string for identifying the driver.
fn compatible(&self) -> &str;

@ -29,7 +29,7 @@
// the first function to run.
mod arch;
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@ -39,12 +39,32 @@ mod interface;
mod panic_wait;
mod print;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
use interface::console::All;
/// Early init code.
///
/// Concerned with with initializing `BSP` and `arch` parts.
///
/// # 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() -> ! {
for i in bsp::device_drivers().iter() {
if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure, the return value of
// `bsp::console()` is already in functioning state.
panic!("Error loading driver: {}", i.compatible())
}
}
bsp::post_driver_init();
// Run the BSP's initialization code.
bsp::init();
// Transition from unsafe to safe.
kernel_main()
}
/// The main function running after the early init.
fn kernel_main() -> ! {
use interface::console::All;
// UART should be functional now. Wait for user to hit Enter.
loop {

@ -4,10 +4,8 @@
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
/// init code.
///
/// # Safety
///
@ -22,5 +20,5 @@ pub unsafe fn init() -> ! {
// Zero out the .bss section.
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
crate::kernel_init()
}

@ -116,22 +116,7 @@ diff -uNr 06_drivers_gpio_uart/src/arch/aarch64.rs 07_uart_chainloader/src/arch/
diff -uNr 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 07_uart_chainloader/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
--- 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
+++ 07_uart_chainloader/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs
@@ -50,10 +50,12 @@
/// shifting out the last bit).
TX_IDLE OFFSET(6) NUMBITS(1) [],
- /// This bit is set if the transmit FIFO can accept at least one byte.
+ /// This bit is set if the transmit FIFO can accept at least
+ /// one byte.
TX_EMPTY OFFSET(5) NUMBITS(1) [],
- /// This bit is set if the receive FIFO holds at least 1 symbol.
+ /// This bit is set if the receive FIFO holds at least 1
+ /// symbol.
DATA_READY OFFSET(0) NUMBITS(1) []
],
@@ -247,6 +249,15 @@
@@ -247,6 +247,15 @@
let mut r = &self.inner;
r.lock(|inner| fmt::Write::write_fmt(inner, args))
}
@ -147,7 +132,7 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/driver/bcm/bcm2xxx_mini_uart.rs 07_uart_c
}
impl interface::console::Read for MiniUart {
@@ -263,14 +274,14 @@
@@ -263,14 +272,14 @@
}
// Read one character.
@ -216,16 +201,6 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/rpi3.rs 07_uart_chainloader/src/bsp/rpi3.
//--------------------------------------------------------------------------------------------------
// Global BSP driver instances
//--------------------------------------------------------------------------------------------------
@@ -34,8 +37,7 @@
&MINI_UART
}
-/// Return an array of references to all `DeviceDriver` compatible `BSP`
-/// drivers.
+/// Return an array of references to all `DeviceDriver` compatible `BSP` drivers.
///
/// # Safety
///
diff -uNr 06_drivers_gpio_uart/src/interface.rs 07_uart_chainloader/src/interface.rs
--- 06_drivers_gpio_uart/src/interface.rs
@ -259,20 +234,25 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
// the first function to run.
mod arch;
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_entry()`.
-// `_start()` then calls `runtime_init::init()`, which on completion, jumps to `kernel_init()`.
+// `_start()` then calls `relocate::relocate_self()`.
+mod relocate;
+
+// `relocate::relocate_self()` calls `runtime_init::init()`, which on completion, jumps to
+// `kernel_entry()`.
+// `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@@ -46,18 +50,48 @@
// Run the BSP's initialization code.
bsp::init();
@@ -66,25 +70,48 @@
fn kernel_main() -> ! {
use interface::console::All;
- println!("[0] Booting on: {}", bsp::board_name());
- // UART should be functional now. Wait for user to hit Enter.
- loop {
- if bsp::console().read_char() == '
' {
- break;
- }
+ println!(" __ __ _ _ _ _ ");
+ println!("| \/ (_)_ _ (_) | ___ __ _ __| |");
+ println!("| |\/| | | ' \| | |__/ _ \/ _` / _` |");
@ -290,8 +270,10 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
+ // Notify raspbootcom to send the binary.
+ for _ in 0..3 {
+ bsp::console().write_char(3 as char);
+ }
}
- println!("[0] Booting on: {}", bsp::board_name());
-
- println!("[1] Drivers loaded:");
- for (i, driver) in bsp::device_drivers().iter().enumerate() {
- println!(" {}. {}", i + 1, driver.compatible());
@ -383,20 +365,18 @@ diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.
diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runtime_init.rs
--- 06_drivers_gpio_uart/src/runtime_init.rs
+++ 07_uart_chainloader/src/runtime_init.rs
@@ -4,23 +4,41 @@
@@ -4,21 +4,39 @@
//! Rust runtime initialization code.
-/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
-/// kernel entry.
-/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
-/// init code.
+/// We are outsmarting the compiler here by using a trait as a layer of indirection. Because we are
+/// generating PIC code, a static dispatch to `init()` would generate a relative jump from the
+/// callee to `init()`. However, when calling `init()`, code just finished copying the binary to the
+/// actual link-time address, and hence is still running at whatever location the previous loader
+/// has put it. So we do not want a relative jump, because it would not jump to the relocated code.
///
-/// Called from `BSP` code.
-///
-/// # Safety
-///
-/// - Only a single core must be active and running this function.
@ -408,10 +388,8 @@ diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runti
+/// By indirecting through a trait object, we can make use of the property that vtables store
+/// absolute addresses. So calling `init()` this way will kick execution to the relocated binary.
+pub trait RunTimeInit {
+ /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
+ /// kernel entry.
+ ///
+ /// Called from `BSP` code.
+ /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
+ /// init code.
+ ///
+ /// # Safety
+ ///
@ -426,7 +404,7 @@ diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runti
+ // Zero out the .bss section.
+ r0::zero_bss(&mut __bss_start, &mut __bss_end);
+
+ crate::kernel_entry()
+ crate::kernel_init()
}
+}
@ -435,7 +413,7 @@ diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runti
+struct Traitor;
+impl RunTimeInit for Traitor {}
- crate::kernel_entry()
- crate::kernel_init()
+/// Give the callee a `RunTimeInit` trait object.
+pub fn get() -> &'static dyn RunTimeInit {
+ &Traitor {}

Binary file not shown.

Binary file not shown.

@ -35,6 +35,13 @@ pub unsafe extern "C" fn _start() -> ! {
pub use asm::nop;
/// Spin for `n` cycles.
pub fn spin_for_cycles(n: usize) {
for _ in 0..n {
asm::nop();
}
}
/// Pause execution on the calling CPU core.
#[inline(always)]
pub fn wait_forever() -> ! {

@ -113,15 +113,11 @@ impl GPIOInner {
// Enable pins 14 and 15.
self.GPPUD.set(0);
for _ in 0..150 {
arch::nop();
}
arch::spin_for_cycles(150);
self.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK14::AssertClock + GPPUDCLK0::PUDCLK15::AssertClock);
for _ in 0..150 {
arch::nop();
}
arch::spin_for_cycles(150);
self.GPPUDCLK0.set(0);
}

@ -46,18 +46,8 @@ pub fn device_drivers() -> [&'static dyn interface::driver::DeviceDriver; 2] {
[&GPIO, &MINI_UART]
}
/// The BSP's main initialization function.
///
/// Called early on kernel start.
pub fn init() {
for i in device_drivers().iter() {
if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure, the return value of
// `bsp::console()` is already in functioning state.
panic!("Error loading driver: {}", i.compatible())
}
}
/// BSP initialization code that runs after driver init.
pub fn post_driver_init() {
// Configure MiniUart's output pins.
GPIO.map_mini_uart();
}

@ -97,7 +97,7 @@ pub mod driver {
/// Driver result type, e.g. for indicating successful driver init.
pub type Result = core::result::Result<(), ()>;
/// Device Driver operations.
/// Device Driver functions.
pub trait DeviceDriver {
/// Return a compatibility string for identifying the driver.
fn compatible(&self) -> &str;

@ -33,7 +33,7 @@ mod arch;
mod relocate;
// `relocate::relocate_self()` calls `runtime_init::init()`, which on completion, jumps to
// `kernel_entry()`.
// `kernel_init()`.
mod runtime_init;
// Conditionally includes the selected `BSP` code.
@ -43,12 +43,32 @@ mod interface;
mod panic_wait;
mod print;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
use interface::console::All;
/// Early init code.
///
/// Concerned with with initializing `BSP` and `arch` parts.
///
/// # 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() -> ! {
for i in bsp::device_drivers().iter() {
if let Err(()) = i.init() {
// This message will only be readable if, at the time of failure, the return value of
// `bsp::console()` is already in functioning state.
panic!("Error loading driver: {}", i.compatible())
}
}
bsp::post_driver_init();
// Run the BSP's initialization code.
bsp::init();
// Transition from unsafe to safe.
kernel_main()
}
/// The main function running after the early init.
fn kernel_main() -> ! {
use interface::console::All;
println!(" __ __ _ _ _ _ ");
println!("| \\/ (_)_ _ (_) | ___ __ _ __| |");

@ -13,10 +13,8 @@
/// By indirecting through a trait object, we can make use of the property that vtables store
/// absolute addresses. So calling `init()` this way will kick execution to the relocated binary.
pub trait RunTimeInit {
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then calls the
/// kernel entry.
///
/// Called from `BSP` code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
/// init code.
///
/// # Safety
///
@ -31,7 +29,7 @@ pub trait RunTimeInit {
// Zero out the .bss section.
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
crate::kernel_init()
}
}

@ -13,7 +13,8 @@ DIFF=$(
-x target \
$1 $2 \
| sed -r "s/[12][90][127][90]-.*//g" \
| sed -r "s/[[:space:]]*$//g"
| sed -r "s/[[:space:]]*$//g" \
| sed -r "s/%/modulo/g"
)
HEADER="## Diff to previous"

Loading…
Cancel
Save