22
33## tl;dr
44
5- - We extend ` boot.s ` to call into Rust code for the first time. There, we zero the [ bss] section
6- before execution is halted with a call to ` panic() ` .
5+ - We extend ` boot.s ` to call into Rust code for the first time. Before the jump
6+ to Rust happens, a bit of runtime init work is done.
7+ - The Rust code being called just halts execution with a call to ` panic!() ` .
78- Check out ` make qemu ` again to see the additional code run.
89
910## Notable additions
1213 - New sections: ` .rodata ` , ` .got ` , ` .data ` , ` .bss ` .
1314 - A dedicated place for linking boot-time arguments that need to be read by ` _start() ` .
1415- ` _start() ` in ` _arch/__arch_name__/cpu/boot.s ` :
15- 1 . Halt core if core != core0.
16- 1 . Set up the ` stack pointer ` .
17- 1 . Jump to the ` _start_rust() ` function, defined in ` arch/__arch_name__/cpu/boot.rs ` .
18- - ` runtime_init ()` in ` runtime_init .rs` :
19- - Zeros the ` .bss ` section.
16+ 1 . Halts core if core != core0.
17+ 1 . Initializes the ` DRAM ` by zeroing the [ bss ] section .
18+ 1 . Sets up the ` stack pointer ` .
19+ 1 . Jumps to the ` _start_rust ()` function, defined in ` arch/__arch_name__/cpu/boot .rs` .
20+ - ` _start_rust() ` :
2021 - Calls ` kernel_init() ` , which calls ` panic!() ` , which eventually halts core0 as well.
2122- The library now uses the [ cortex-a] crate, which provides zero-overhead abstractions and wraps
2223 ` unsafe ` parts when dealing with the CPU's resources.
@@ -64,12 +65,8 @@ diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile
6465diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
6566--- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs
6667+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
67- @@ -11,5 +11,23 @@
68- //!
69- //! crate::cpu::boot::arch_boot
68+ @@ -13,3 +13,15 @@
7069
71- + use crate::runtime_init;
72- +
7370 // Assembly counterpart to this file.
7471 global_asm!(include_str!("boot.s"));
7572+
@@ -80,13 +77,9 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arc
8077+ /// The Rust entry of the `kernel` binary.
8178+ ///
8279+ /// The function is called from the assembly `_start` function.
83- + ///
84- + /// # Safety
85- + ///
86- + /// - The `bss` section is not initialized yet. The code must not use or reference it in any way.
8780+ #[no_mangle]
8881+ pub unsafe fn _start_rust() -> ! {
89- + runtime_init::runtime_init ()
82+ + crate::kernel_init ()
9083+ }
9184
9285diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s
@@ -117,7 +110,7 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
117110 // Public Code
118111 //--------------------------------------------------------------------------------------------------
119112 .section .text._start
120- @@ -11,6 +29,22 @@
113+ @@ -11,9 +29,38 @@
121114 // fn _start()
122115 //------------------------------------------------------------------------------
123116 _start:
@@ -126,10 +119,22 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
126119+ and x1, x1, _core_id_mask
127120+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
128121+ cmp x1, x2
129- + b.ne 1f
122+ + b.ne parking_loop
123+ +
124+ + // If execution reaches here, it is the boot core.
125+ +
126+ + // Initialize DRAM.
127+ + ADR_REL x0, __bss_start
128+ + ADR_REL x1, __bss_end_exclusive
130129+
131- + // If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
130+ + bss_init_loop:
131+ + cmp x0, x1
132+ + b.eq prepare_rust
133+ + stp xzr, xzr, [x0], #16
134+ + b bss_init_loop
132135+
136+ + // Prepare the jump to Rust code.
137+ + prepare_rust:
133138+ // Set the stack pointer.
134139+ ADR_REL x0, __boot_core_stack_end_exclusive
135140+ mov sp, x0
@@ -138,8 +143,14 @@ diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch
138143+ b _start_rust
139144+
140145 // Infinitely wait for events (aka "park the core").
141- 1: wfe
142- b 1b
146+ - 1: wfe
147+ - b 1b
148+ + parking_loop:
149+ + wfe
150+ + b parking_loop
151+
152+ .size _start, . - _start
153+ .type _start, function
143154
144155diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs
145156--- 01_wait_forever/src/_arch/aarch64/cpu.rs
@@ -194,7 +205,7 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/ras
194205diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld
195206--- 01_wait_forever/src/bsp/raspberrypi/link.ld
196207+++ 02_runtime_init/src/bsp/raspberrypi/link.ld
197- @@ -11,17 +11,45 @@
208+ @@ -11,17 +11,43 @@
198209 PHDRS
199210 {
200211 segment_rx PT_LOAD FLAGS(5); /* 5 == RX */
@@ -230,70 +241,25 @@ diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/ra
230241+ ***********************************************************************************************/
231242+ .data : { *(.data*) } :segment_rw
232243+
233- + /* Section is zeroed in u64 chunks, align start and end to 8 bytes */
234- + .bss : ALIGN(8 )
244+ + /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
245+ + .bss : ALIGN(16 )
235246+ {
236247+ __bss_start = .;
237248+ *(.bss*);
238- + . = ALIGN(8);
239- +
240- + . += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
241- + __bss_end_inclusive = . - 8;
249+ + . = ALIGN(16);
250+ + __bss_end_exclusive = .;
242251+ } :NONE
243252 }
244253
245- diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs
246- --- 01_wait_forever/src/bsp/raspberrypi/memory.rs
247- +++ 02_runtime_init/src/bsp/raspberrypi/memory.rs
248- @@ -0,0 +1,37 @@
249- + // SPDX-License-Identifier: MIT OR Apache-2.0
250- + //
251- + // Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
252- +
253- + //! BSP Memory Management.
254- +
255- + use core::{cell::UnsafeCell, ops::RangeInclusive};
256- +
257- + //--------------------------------------------------------------------------------------------------
258- + // Private Definitions
259- + //--------------------------------------------------------------------------------------------------
260- +
261- + // Symbols from the linker script.
262- + extern "Rust" {
263- + static __bss_start: UnsafeCell<u64>;
264- + static __bss_end_inclusive: UnsafeCell<u64>;
265- + }
266- +
267- + //--------------------------------------------------------------------------------------------------
268- + // Public Code
269- + //--------------------------------------------------------------------------------------------------
270- +
271- + /// Return the inclusive range spanning the .bss section.
272- + ///
273- + /// # Safety
274- + ///
275- + /// - Values are provided by the linker script and must be trusted as-is.
276- + /// - The linker-provided addresses must be u64 aligned.
277- + pub fn bss_range_inclusive() -> RangeInclusive<*mut u64> {
278- + let range;
279- + unsafe {
280- + range = RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get());
281- + }
282- + assert!(!range.is_empty());
283- +
284- + range
285- + }
286-
287254diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs
288255--- 01_wait_forever/src/bsp/raspberrypi.rs
289256+++ 02_runtime_init/src/bsp/raspberrypi.rs
290- @@ -4,4 +4,5 @@
257+ @@ -4,4 +4,4 @@
291258
292259 //! Top-level BSP file for the Raspberry Pi 3 and 4.
293260
294261- // Coming soon.
295262+ pub mod cpu;
296- + pub mod memory;
297263
298264diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
299265--- 01_wait_forever/src/cpu.rs
@@ -316,24 +282,19 @@ diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
316282diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
317283--- 01_wait_forever/src/main.rs
318284+++ 02_runtime_init/src/main.rs
319- @@ -102,14 +102,25 @@
285+ @@ -102,8 +102,8 @@
320286 //!
321287 //! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`.
322288 //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
323- + //! 2. Once finished with architectural setup, the arch code calls [`runtime_init::runtime_init()`].
324- + //!
325- + //! [`runtime_init::runtime_init()`]: runtime_init/fn.runtime_init.html
289+ + //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
326290
327291- #![feature(asm)]
328292 #![feature(global_asm)]
329293 #![no_main]
330294 #![no_std]
331-
332- mod bsp;
295+ @@ -112,4 +112,11 @@
333296 mod cpu;
334- + mod memory;
335297 mod panic_wait;
336- + mod runtime_init;
337298
338299- // Kernel code coming next tutorial.
339300+ /// Early init code.
@@ -345,41 +306,6 @@ diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
345306+ panic!()
346307+ }
347308
348- diff -uNr 01_wait_forever/src/memory.rs 02_runtime_init/src/memory.rs
349- --- 01_wait_forever/src/memory.rs
350- +++ 02_runtime_init/src/memory.rs
351- @@ -0,0 +1,30 @@
352- + // SPDX-License-Identifier: MIT OR Apache-2.0
353- + //
354- + // Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
355- +
356- + //! Memory Management.
357- +
358- + use core::ops::RangeInclusive;
359- +
360- + //--------------------------------------------------------------------------------------------------
361- + // Public Code
362- + //--------------------------------------------------------------------------------------------------
363- +
364- + /// Zero out an inclusive memory range.
365- + ///
366- + /// # Safety
367- + ///
368- + /// - `range.start` and `range.end` must be valid.
369- + /// - `range.start` and `range.end` must be `T` aligned.
370- + pub unsafe fn zero_volatile<T>(range: RangeInclusive<*mut T>)
371- + where
372- + T: From<u8>,
373- + {
374- + let mut ptr = *range.start();
375- + let end_inclusive = *range.end();
376- +
377- + while ptr <= end_inclusive {
378- + core::ptr::write_volatile(ptr, T::from(0));
379- + ptr = ptr.offset(1);
380- + }
381- + }
382-
383309diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
384310--- 01_wait_forever/src/panic_wait.rs
385311+++ 02_runtime_init/src/panic_wait.rs
@@ -396,46 +322,4 @@ diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
396322+ cpu::wait_forever()
397323 }
398324
399- diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.rs
400- --- 01_wait_forever/src/runtime_init.rs
401- +++ 02_runtime_init/src/runtime_init.rs
402- @@ -0,0 +1,37 @@
403- + // SPDX-License-Identifier: MIT OR Apache-2.0
404- + //
405- + // Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
406- +
407- + //! Rust runtime initialization code.
408- +
409- + use crate::{bsp, memory};
410- +
411- + //--------------------------------------------------------------------------------------------------
412- + // Private Code
413- + //--------------------------------------------------------------------------------------------------
414- +
415- + /// Zero out the .bss section.
416- + ///
417- + /// # Safety
418- + ///
419- + /// - Must only be called pre `kernel_init()`.
420- + #[inline(always)]
421- + unsafe fn zero_bss() {
422- + memory::zero_volatile(bsp::memory::bss_range_inclusive());
423- + }
424- +
425- + //--------------------------------------------------------------------------------------------------
426- + // Public Code
427- + //--------------------------------------------------------------------------------------------------
428- +
429- + /// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
430- + /// init code.
431- + ///
432- + /// # Safety
433- + ///
434- + /// - Only a single core must be active and running this function.
435- + pub unsafe fn runtime_init() -> ! {
436- + zero_bss();
437- +
438- + crate::kernel_init()
439- + }
440-
441325```
0 commit comments