rust-raspberrypi-OS-tutorials/02_runtime_init/README.md

294 lines
8.6 KiB
Markdown
Raw Normal View History

2019-09-25 09:56:41 +00:00
# Tutorial 02 - Runtime Init
## tl;dr
2020-10-04 20:27:28 +00:00
- We extend `cpu.S` to call into Rust code for the first time. There, we zero the [bss] section
before execution is halted with a call to `panic()`.
- Check out `make qemu` again to see the additional code run.
2020-03-28 12:27:23 +00:00
## Notable additions
2019-09-25 09:56:41 +00:00
- More sections in linker script:
- `.rodata`, `.data`
- `.bss`
- `_start()`:
- Halt core if core != `core0`.
2020-03-28 12:27:23 +00:00
- `core0` jumps to the `runtime_init()` Rust function.
2019-12-30 21:31:55 +00:00
- `runtime_init()` in `runtime_init.rs`
2019-09-25 09:56:41 +00:00
- Zeros the `.bss` section.
2020-03-28 12:27:23 +00:00
- Calls `kernel_init()`, which calls `panic!()`, which eventually halts `core0` as well.
2019-09-25 09:56:41 +00:00
2019-12-30 23:00:09 +00:00
[bss]: https://en.wikipedia.org/wiki/.bss
2019-09-25 09:56:41 +00:00
## Diff to previous
2020-03-28 14:42:42 +00:00
```diff
diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml
--- 01_wait_forever/Cargo.toml
+++ 02_runtime_init/Cargo.toml
@@ -4,6 +4,9 @@
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2018"
+[profile.release]
+lto = true
+
# The features section is used to select the target board.
[features]
default = []
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs
--- 01_wait_forever/src/_arch/aarch64/cpu.rs
+++ 02_runtime_init/src/_arch/aarch64/cpu.rs
@@ -6,3 +6,21 @@
// Assembly counterpart to this file.
global_asm!(include_str!("cpu.S"));
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Pause execution on the core.
+#[inline(always)]
+pub fn wait_forever() -> ! {
+ unsafe {
+ loop {
+ #[rustfmt::skip]
+ asm!(
+ "wfe",
+ options(nomem, nostack, preserves_flags)
+ );
+ }
+ }
+}
2020-03-28 14:42:42 +00:00
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.S 02_runtime_init/src/_arch/aarch64/cpu.S
--- 01_wait_forever/src/_arch/aarch64/cpu.S
+++ 02_runtime_init/src/_arch/aarch64/cpu.S
@@ -7,5 +7,15 @@
.global _start
_start:
-1: wfe // Wait for event
- b 1b // In case an event happened, jump back to 1
+ mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register
+ and x1, x1, #3 // Clear all bits except [1:0], which hold core id
+ cbz x1, 2f // Jump to label 2 if we are core 0
+1: wfe // Wait for event
+ b 1b // In case an event happened, jump back to 1
+2: // If we are here, we are core0
+ ldr x1, =_start // Load address of function "_start()"
+ mov sp, x1 // Set start of stack to before our code, aka first
+ // address before "_start()"
+ bl runtime_init // Jump to the "runtime_init()" kernel function
+ b 1b // We should never reach here. But just in case,
+ // park this core aswell
diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld
--- 01_wait_forever/src/bsp/raspberrypi/link.ld
+++ 02_runtime_init/src/bsp/raspberrypi/link.ld
2020-11-01 20:32:53 +00:00
@@ -13,5 +13,27 @@
2020-03-28 14:42:42 +00:00
*(.text._start) *(.text*)
}
+ .rodata :
+ {
+ *(.rodata*)
+ }
+
+ .data :
+ {
+ *(.data*)
+ }
+
+ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
+ .bss ALIGN(8):
+ {
+ __bss_start = .;
+ *(.bss*);
+ . = ALIGN(8);
2020-11-01 20:32:53 +00:00
+
+ /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
+ . += 8;
+ __bss_end_inclusive = . - 8;
2020-03-28 14:42:42 +00:00
+ }
+
/DISCARD/ : { *(.comment*) }
}
diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs
--- 01_wait_forever/src/bsp/raspberrypi/memory.rs
+++ 02_runtime_init/src/bsp/raspberrypi/memory.rs
2020-11-01 20:32:53 +00:00
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
2021-01-01 10:28:32 +00:00
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
+
+//! BSP Memory Management.
+
+use core::{cell::UnsafeCell, ops::RangeInclusive};
+
+//--------------------------------------------------------------------------------------------------
+// Private Definitions
+//--------------------------------------------------------------------------------------------------
+
+// Symbols from the linker script.
+extern "Rust" {
+ static __bss_start: UnsafeCell<u64>;
+ static __bss_end_inclusive: UnsafeCell<u64>;
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Return the inclusive range spanning the .bss section.
+///
+/// # Safety
+///
+/// - Values are provided by the linker script and must be trusted as-is.
+/// - The linker-provided addresses must be u64 aligned.
+pub fn bss_range_inclusive() -> RangeInclusive<*mut u64> {
2020-11-01 20:32:53 +00:00
+ let range;
+ unsafe {
+ range = RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get());
+ }
+ assert!(!range.is_empty());
+
+ range
+}
diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs
--- 01_wait_forever/src/bsp/raspberrypi.rs
+++ 02_runtime_init/src/bsp/raspberrypi.rs
@@ -4,4 +4,4 @@
//! Top-level BSP file for the Raspberry Pi 3 and 4.
-// Coming soon.
+pub mod memory;
2020-03-28 14:42:42 +00:00
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
@@ -97,10 +97,20 @@
#![no_main]
#![no_std]
-// `mod cpu` provides the `_start()` function, the first function to run.
+// `mod cpu` provides the `_start()` function, the first function to run. `_start()` then calls
+// `runtime_init()`, which jumps to `kernel_init()`.
mod bsp;
mod cpu;
+mod memory;
mod panic_wait;
+mod runtime_init;
-// Kernel code coming next tutorial.
+/// 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/memory.rs 02_runtime_init/src/memory.rs
--- 01_wait_forever/src/memory.rs
+++ 02_runtime_init/src/memory.rs
2020-11-01 20:32:53 +00:00
@@ -0,0 +1,30 @@
2020-03-28 14:42:42 +00:00
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
2021-01-01 10:28:32 +00:00
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
2020-03-28 14:42:42 +00:00
+
+//! Memory Management.
+
+use core::ops::RangeInclusive;
2020-03-28 14:42:42 +00:00
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Zero out an inclusive memory range.
2020-03-28 14:42:42 +00:00
+///
+/// # Safety
+///
+/// - `range.start` and `range.end` must be valid.
+/// - `range.start` and `range.end` must be `T` aligned.
+pub unsafe fn zero_volatile<T>(range: RangeInclusive<*mut T>)
2020-03-28 14:42:42 +00:00
+where
+ T: From<u8>,
+{
+ let mut ptr = *range.start();
+ let end_inclusive = *range.end();
2020-03-28 14:42:42 +00:00
+
2020-11-01 20:32:53 +00:00
+ while ptr <= end_inclusive {
2020-03-28 14:42:42 +00:00
+ core::ptr::write_volatile(ptr, T::from(0));
+ ptr = ptr.offset(1);
+ }
+}
diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
--- 01_wait_forever/src/panic_wait.rs
+++ 02_runtime_init/src/panic_wait.rs
2021-01-01 10:28:32 +00:00
@@ -4,9 +4,10 @@
//! A panic handler that infinitely waits.
+use crate::cpu;
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
- unimplemented!()
+ cpu::wait_forever()
}
2020-03-28 14:42:42 +00:00
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,38 @@
2020-03-28 14:42:42 +00:00
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
2021-01-01 10:28:32 +00:00
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
2020-03-28 14:42:42 +00:00
+
+//! Rust runtime initialization code.
+
+use crate::{bsp, memory};
2020-03-28 14:42:42 +00:00
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+/// Zero out the .bss section.
+///
+/// # Safety
+///
+/// - Must only be called pre `kernel_init()`.
+#[inline(always)]
+unsafe fn zero_bss() {
+ memory::zero_volatile(bsp::memory::bss_range_inclusive());
2020-03-28 14:42:42 +00:00
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
+/// init code.
+///
+/// # Safety
+///
+/// - Only a single core must be active and running this function.
+#[no_mangle]
2020-10-05 22:01:50 +00:00
+pub unsafe fn runtime_init() -> ! {
2020-03-28 14:42:42 +00:00
+ zero_bss();
+
+ crate::kernel_init()
+}
```