Skip to content

Commit

Permalink
Init DRAM in assembly instead of Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
andre-richter committed Jul 2, 2021
1 parent 39a066c commit 7f66600
Show file tree
Hide file tree
Showing 136 changed files with 872 additions and 2,585 deletions.
200 changes: 42 additions & 158 deletions 02_runtime_init/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## tl;dr

- We extend `boot.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()`.
- We extend `boot.s` to call into Rust code for the first time. Before the jump
to Rust happens, a bit of runtime init work is done.
- The Rust code being called just halts execution with a call to `panic!()`.
- Check out `make qemu` again to see the additional code run.

## Notable additions
Expand All @@ -12,11 +13,11 @@
- New sections: `.rodata`, `.got`, `.data`, `.bss`.
- A dedicated place for linking boot-time arguments that need to be read by `_start()`.
- `_start()` in `_arch/__arch_name__/cpu/boot.s`:
1. Halt core if core != core0.
1. Set up the `stack pointer`.
1. Jump to the `_start_rust()` function, defined in `arch/__arch_name__/cpu/boot.rs`.
- `runtime_init()` in `runtime_init.rs`:
- Zeros the `.bss` section.
1. Halts core if core != core0.
1. Initializes the `DRAM` by zeroing the [bss] section.
1. Sets up the `stack pointer`.
1. Jumps to the `_start_rust()` function, defined in `arch/__arch_name__/cpu/boot.rs`.
- `_start_rust()`:
- Calls `kernel_init()`, which calls `panic!()`, which eventually halts core0 as well.
- The library now uses the [cortex-a] crate, which provides zero-overhead abstractions and wraps
`unsafe` parts when dealing with the CPU's resources.
Expand Down Expand Up @@ -64,12 +65,8 @@ diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
@@ -11,5 +11,23 @@
//!
//! crate::cpu::boot::arch_boot
@@ -13,3 +13,15 @@

+use crate::runtime_init;
+
// Assembly counterpart to this file.
global_asm!(include_str!("boot.s"));
+
Expand All @@ -80,13 +77,9 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arc
+/// The Rust entry of the `kernel` binary.
+///
+/// The function is called from the assembly `_start` function.
+///
+/// # Safety
+///
+/// - The `bss` section is not initialized yet. The code must not use or reference it in any way.
+#[no_mangle]
+pub unsafe fn _start_rust() -> ! {
+ runtime_init::runtime_init()
+ crate::kernel_init()
+}

diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s
Expand Down Expand Up @@ -117,7 +110,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
// Public Code
//--------------------------------------------------------------------------------------------------
.section .text._start
@@ -11,6 +29,22 @@
@@ -11,9 +29,38 @@
// fn _start()
//------------------------------------------------------------------------------
_start:
Expand All @@ -126,10 +119,22 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
+ and x1, x1, _core_id_mask
+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
+ cmp x1, x2
+ b.ne 1f
+ b.ne parking_loop
+
+ // If execution reaches here, it is the boot core.
+
+ // Initialize DRAM.
+ ADR_REL x0, __bss_start
+ ADR_REL x1, __bss_end_exclusive
+
+ // If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
+bss_init_loop:
+ cmp x0, x1
+ b.eq prepare_rust
+ stp xzr, xzr, [x0], #16
+ b bss_init_loop
+
+ // Prepare the jump to Rust code.
+prepare_rust:
+ // Set the stack pointer.
+ ADR_REL x0, __boot_core_stack_end_exclusive
+ mov sp, x0
Expand All @@ -138,8 +143,14 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
+ b _start_rust
+
// Infinitely wait for events (aka "park the core").
1: wfe
b 1b
-1: wfe
- b 1b
+parking_loop:
+ wfe
+ b parking_loop

.size _start, . - _start
.type _start, function

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
Expand Down Expand Up @@ -194,7 +205,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/ras
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
@@ -11,17 +11,45 @@
@@ -11,17 +11,43 @@
PHDRS
{
segment_rx PT_LOAD FLAGS(5); /* 5 == RX */
Expand Down Expand Up @@ -230,70 +241,25 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/ra
+ ***********************************************************************************************/
+ .data : { *(.data*) } :segment_rw
+
+ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
+ .bss : ALIGN(8)
+ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
+ .bss : ALIGN(16)
+ {
+ __bss_start = .;
+ *(.bss*);
+ . = ALIGN(8);
+
+ . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
+ __bss_end_inclusive = . - 8;
+ . = ALIGN(16);
+ __bss_end_exclusive = .;
+ } :NONE
}

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
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// 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> {
+ 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,5 @@
@@ -4,4 +4,4 @@

//! Top-level BSP file for the Raspberry Pi 3 and 4.

-// Coming soon.
+pub mod cpu;
+pub mod memory;

diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
--- 01_wait_forever/src/cpu.rs
Expand All @@ -316,24 +282,19 @@ diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
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
@@ -102,14 +102,25 @@
@@ -102,8 +102,8 @@
//!
//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`.
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
+//! 2. Once finished with architectural setup, the arch code calls [`runtime_init::runtime_init()`].
+//!
+//! [`runtime_init::runtime_init()`]: runtime_init/fn.runtime_init.html
+//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.

-#![feature(asm)]
#![feature(global_asm)]
#![no_main]
#![no_std]

mod bsp;
@@ -112,4 +112,11 @@
mod cpu;
+mod memory;
mod panic_wait;
+mod runtime_init;

-// Kernel code coming next tutorial.
+/// Early init code.
Expand All @@ -345,41 +306,6 @@ diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
+ 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
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
+
+//! Memory Management.
+
+use core::ops::RangeInclusive;
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// Zero out an inclusive memory range.
+///
+/// # 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>)
+where
+ T: From<u8>,
+{
+ let mut ptr = *range.start();
+ let end_inclusive = *range.end();
+
+ while ptr <= end_inclusive {
+ 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
Expand All @@ -396,46 +322,4 @@ diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
+ cpu::wait_forever()
}

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,37 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
+
+//! Rust runtime initialization code.
+
+use crate::{bsp, memory};
+
+//--------------------------------------------------------------------------------------------------
+// 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());
+}
+
+//--------------------------------------------------------------------------------------------------
+// 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.
+pub unsafe fn runtime_init() -> ! {
+ zero_bss();
+
+ crate::kernel_init()
+}

```
8 changes: 1 addition & 7 deletions 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
//!
//! crate::cpu::boot::arch_boot

use crate::runtime_init;

// Assembly counterpart to this file.
global_asm!(include_str!("boot.s"));

Expand All @@ -23,11 +21,7 @@ global_asm!(include_str!("boot.s"));
/// The Rust entry of the `kernel` binary.
///
/// The function is called from the assembly `_start` function.
///
/// # Safety
///
/// - The `bss` section is not initialized yet. The code must not use or reference it in any way.
#[no_mangle]
pub unsafe fn _start_rust() -> ! {
runtime_init::runtime_init()
crate::kernel_init()
}
21 changes: 17 additions & 4 deletions 02_runtime_init/src/_arch/aarch64/cpu/boot.s
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,22 @@ _start:
and x1, x1, _core_id_mask
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
cmp x1, x2
b.ne 1f
b.ne parking_loop

// If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
// If execution reaches here, it is the boot core.

// Initialize DRAM.
ADR_REL x0, __bss_start
ADR_REL x1, __bss_end_exclusive

bss_init_loop:
cmp x0, x1
b.eq prepare_rust
stp xzr, xzr, [x0], #16
b bss_init_loop

// Prepare the jump to Rust code.
prepare_rust:
// Set the stack pointer.
ADR_REL x0, __boot_core_stack_end_exclusive
mov sp, x0
Expand All @@ -46,8 +58,9 @@ _start:
b _start_rust

// Infinitely wait for events (aka "park the core").
1: wfe
b 1b
parking_loop:
wfe
b parking_loop

.size _start, . - _start
.type _start, function
Expand Down
1 change: 0 additions & 1 deletion 02_runtime_init/src/bsp/raspberrypi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@
//! Top-level BSP file for the Raspberry Pi 3 and 4.

pub mod cpu;
pub mod memory;
10 changes: 4 additions & 6 deletions 02_runtime_init/src/bsp/raspberrypi/link.ld
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@ SECTIONS
***********************************************************************************************/
.data : { *(.data*) } :segment_rw

/* Section is zeroed in u64 chunks, align start and end to 8 bytes */
.bss : ALIGN(8)
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
.bss : ALIGN(16)
{
__bss_start = .;
*(.bss*);
. = ALIGN(8);

. += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
__bss_end_inclusive = . - 8;
. = ALIGN(16);
__bss_end_exclusive = .;
} :NONE
}
Loading

0 comments on commit 7f66600

Please sign in to comment.