1198 字
6 分钟
使用Rust在树莓派上编写操作系统 - 02 - 运行时初始化
WARNING本文所有内容均为翻译,原文:Tutorial 02 - Runtime Init;原项目:Operating System development tutorials in Rust on the Raspberry Pi
概述
- 本章扩展了
boot.s,以首次调用Rust代码。在跳转到Rust之前,一些运行时的初始化工作已经完成。 - 本章中被调用的Rust代码只能够通过调用
panic!()宏来停止执行。 - 仍旧是查看
make qemu的输出,以观察新增代码的运行情况。
需要注意的新增代码
- 新增了一些链接脚本(译注:仍位于
link.ld中):- 新增的节包括:
.rodata、.got、.data、.bss。(译注:详情参考ELF文件结构) - 一个专用位置,用于存放
_start()需要读取的引导时链接参数。(译注:新增src/bsp/raspberrypi/cpu.rs)
- 新增的节包括:
_arch/__arch_name__/cpu/boot.s中的_start():- 如果当前核心不是core0,则挂起该核心。
- 初始化
内存,将bss节置为0。 - 为Rust入口准备栈指针
stack pointer。 - 跳转至定义在
arch/__arch_name__/cpu/boot.rs中的_start_rust()函数。
_start_rust()函数:- 调用
kernel_init()函数,从而调用panic!()宏,最终使得core0也被挂起。
- 调用
- 该库目前使用cortex-acrate,该crate提供零开销抽象,并在处理CPU相关操作时封装
unsafe代码。- 具体使用参见
_arch/__arch_name__/cpu.rs中的相关操作。
- 具体使用参见
与上一章代码的区别
diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml--- 01_wait_forever/Cargo.toml+++ 02_runtime_init/Cargo.toml@@ -1,6 +1,6 @@ [package] name = "mingo"-version = "0.1.0"+version = "0.2.0" authors = ["Andre Richter <andre.o.richter@gmail.com>"] edition = "2018"
@@ -21,3 +21,8 @@ ##--------------------------------------------------------------------------------------------------
[dependencies]++# Platform specific dependencies+[target.'cfg(target_arch = "aarch64")'.dependencies]+cortex-a = { version = "6.x.x" }+
diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile--- 01_wait_forever/Makefile+++ 02_runtime_init/Makefile@@ -152,6 +152,8 @@ $(call colorecho, "\nLaunching objdump") @$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \ --section .text \+ --section .rodata \+ --section .got \ $(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
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@@ -13,3 +13,15 @@
// Assembly counterpart to this file. global_asm!(include_str!("boot.s"));++//--------------------------------------------------------------------------------------------------+// Public Code+//--------------------------------------------------------------------------------------------------++/// The Rust entry of the `kernel` binary.+///+/// The function is called from the assembly `_start` function.+#[no_mangle]+pub unsafe fn _start_rust() -> ! {+ crate::kernel_init()+}
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s--- 01_wait_forever/src/_arch/aarch64/cpu/boot.s+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s@@ -3,6 +3,24 @@ // Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
//--------------------------------------------------------------------------------------------------+// Definitions+//--------------------------------------------------------------------------------------------------++// Load the address of a symbol into a register, PC-relative.+//+// The symbol must lie within +/- 4 GiB of the Program Counter.+//+// # Resources+//+// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html+.macro ADR_REL register, symbol+ adrp \register, \symbol+ add \register, \register, #:lo12:\symbol+.endm++.equ _core_id_mask, 0b11++//-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- .section .text._start@@ -11,6 +29,34 @@ // fn _start() //------------------------------------------------------------------------------ _start:+ // Only proceed on the boot core. Park it otherwise.+ mrs x1, MPIDR_EL1+ and x1, x1, _core_id_mask+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs+ cmp x1, x2+ b.ne .L_parking_loop++ // If execution reaches here, it is the boot core.++ // Initialize DRAM.+ ADR_REL x0, __bss_start+ ADR_REL x1, __bss_end_exclusive++.L_bss_init_loop:+ cmp x0, x1+ b.eq .L_prepare_rust+ stp xzr, xzr, [x0], #16+ b .L_bss_init_loop++ // Prepare the jump to Rust code.+.L_prepare_rust:+ // Set the stack pointer.+ ADR_REL x0, __boot_core_stack_end_exclusive+ mov sp, x0++ // Jump to Rust code.+ b _start_rust+ // Infinitely wait for events (aka "park the core"). .L_parking_loop: wfe
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@@ -0,0 +1,26 @@+// SPDX-License-Identifier: MIT OR Apache-2.0+//+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>++//! Architectural processor code.+//!+//! # Orientation+//!+//! Since arch modules are imported into generic modules using the path attribute, the path of this+//! file is:+//!+//! crate::cpu::arch_cpu++use cortex_a::asm;++//--------------------------------------------------------------------------------------------------+// Public Code+//--------------------------------------------------------------------------------------------------++/// Pause execution on the core.+#[inline(always)]+pub fn wait_forever() -> ! {+ loop {+ asm::wfe()+ }+}
diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/raspberrypi/cpu.rs--- 01_wait_forever/src/bsp/raspberrypi/cpu.rs+++ 02_runtime_init/src/bsp/raspberrypi/cpu.rs@@ -0,0 +1,14 @@+// SPDX-License-Identifier: MIT OR Apache-2.0+//+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>++//! BSP Processor code.++//--------------------------------------------------------------------------------------------------+// Public Definitions+//--------------------------------------------------------------------------------------------------++/// Used by `arch` code to find the early boot core.+#[no_mangle]+#[link_section = ".text._start_arguments"]+pub static BOOT_CORE_ID: u64 = 0;
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,43 @@ PHDRS { segment_rx PT_LOAD FLAGS(5); /* 5 == RX */+ segment_rw PT_LOAD FLAGS(6); /* 6 == RW */ }
SECTIONS { . = __rpi_load_addr;+ /* ^ */+ /* | stack */+ /* | growth */+ /* | direction */+ __boot_core_stack_end_exclusive = .; /* | */
/***********************************************************************************************- * Code+ * Code + RO Data + Global Offset Table ***********************************************************************************************/ .text : { KEEP(*(.text._start))+ *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */+ *(.text._start_rust) /* The Rust entry point */+ *(.text*) /* Everything else */ } :segment_rx++ .rodata : ALIGN(8) { *(.rodata*) } :segment_rx+ .got : ALIGN(8) { *(.got) } :segment_rx++ /***********************************************************************************************+ * Data + BSS+ ***********************************************************************************************/+ .data : { *(.data*) } :segment_rw++ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */+ .bss : ALIGN(16)+ {+ __bss_start = .;+ *(.bss*);+ . = ALIGN(16);+ __bss_end_exclusive = .;+ } :NONE }
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 cpu;
diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs--- 01_wait_forever/src/cpu.rs+++ 02_runtime_init/src/cpu.rs@@ -4,4 +4,13 @@
//! Processor code.
+#[cfg(target_arch = "aarch64")]+#[path = "_arch/aarch64/cpu.rs"]+mod arch_cpu;+ mod boot;++//--------------------------------------------------------------------------------------------------+// Architectural Public Reexports+//--------------------------------------------------------------------------------------------------+pub use arch_cpu::wait_forever;
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,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 `kernel_init()`.
-#![feature(asm)] #![feature(global_asm)] #![no_main] #![no_std]@@ -112,4 +112,11 @@ mod cpu; mod panic_wait;
-// 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/panic_wait.rs 02_runtime_init/src/panic_wait.rs--- 01_wait_forever/src/panic_wait.rs+++ 02_runtime_init/src/panic_wait.rs@@ -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() } 使用Rust在树莓派上编写操作系统 - 02 - 运行时初始化
https://zlotus.github.io/2021/08/03/writing-os-in-rust-on-rpi-02/