Skip to content

Commit 0353949

Browse files
committed
README.ES.md -> 02_runtime_init
1 parent ac93ef5 commit 0353949

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed

02_runtime_init/README.ES.md

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
# Tutorial 02 - Inicio de Tiempo de Ejecución
2+
3+
## tl;dr
4+
5+
* Extendimos la funcionalidad de `boot.s` para que sea capaz de llamar código de Rust por primera vez. Antes de que el cambio a Rust ocurra, se realizan algunos trabajos de inicio de tiempo de ejecución (runtime init).
6+
* El código de Rust que es llamado solo pausa la ejecución con una llamada a `panic!()`.
7+
* Ejecuta `make qemu` de nuevo para que puedas ver el código adicional en acción.
8+
9+
## Adiciones importantes
10+
11+
* Adiciones importantes al script `link.ld`:
12+
13+
* Nuevas secciones: `.rodata`, `.got`, `.data`, `.bss`.
14+
15+
* Un lugar totalmente dedicado para enlazar argumentos de tiempo de arranque (boot-time) que necesitan estar listos cuando se llame a `_start()`.
16+
17+
* `_start()` en `_arch/__arch_name__/cpu/boot.s`:
18+
19+
1. Para el núcleo del procesador `if core != core0` (si la variable `core` es diferente de la variable `core0`).
20+
21+
2. Inicializa la [`DRAM`](https://es.wikipedia.org/wiki/DRAM) haciendo ceros la sección de [`bsp`](https://en.wikipedia.org/wiki/.bss).
22+
23+
3. Configura el `stack pointer` (puntero a la memoria *stack*).
24+
25+
4. Salta hacia la función `_start_rust()`, definida en `arch/__arch_name__/cpu/boot.rs`.
26+
27+
. `_start_rust()`:
28+
29+
. Llama a `kernel_init()`, que llama a `panic!()`, que eventualmente también pausa a core0.
30+
31+
. La librería ahora usa el crate [cortex-a](https://github.com/rust-embedded/cortex-a), que nos da abstracciones conocidas como *zero-overhead* y envulve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja con los recursos del procesador.
32+
33+
. Lo puedes ver en acción en `_arch/__arch_name__/cpu.rs`.
34+
35+
## Diff del archivo anterior
36+
37+
```diff
38+
diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml
39+
--- 01_wait_forever/Cargo.toml
40+
+++ 02_runtime_init/Cargo.toml
41+
@@ -1,6 +1,6 @@
42+
[package]
43+
name = "mingo"
44+
-version = "0.1.0"
45+
+version = "0.2.0"
46+
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
47+
edition = "2021"
48+
49+
@@ -21,3 +21,7 @@
50+
##--------------------------------------------------------------------------------------------------
51+
52+
[dependencies]
53+
+
54+
+# Platform specific dependencies
55+
+[target.'cfg(target_arch = "aarch64")'.dependencies]
56+
+cortex-a = { version = "7.x.x" }
57+
58+
diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile
59+
--- 01_wait_forever/Makefile
60+
+++ 02_runtime_init/Makefile
61+
@@ -153,6 +153,8 @@
62+
$(call colorecho, "\nLaunching objdump")
63+
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
64+
--section .text \
65+
+ --section .rodata \
66+
+ --section .got \
67+
$(KERNEL_ELF) | rustfilt
68+
69+
##------------------------------------------------------------------------------
70+
71+
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.rs 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
72+
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.rs
73+
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.rs
74+
@@ -13,3 +13,15 @@
75+
76+
// Assembly counterpart to this file.
77+
core::arch::global_asm!(include_str!("boot.s"));
78+
+
79+
+//--------------------------------------------------------------------------------------------------
80+
+// Public Code
81+
+//--------------------------------------------------------------------------------------------------
82+
+
83+
+/// The Rust entry of the `kernel` binary.
84+
+///
85+
+/// The function is called from the assembly `_start` function.
86+
+#[no_mangle]
87+
+pub unsafe fn _start_rust() -> ! {
88+
+ crate::kernel_init()
89+
+}
90+
91+
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu/boot.s 02_runtime_init/src/_arch/aarch64/cpu/boot.s
92+
--- 01_wait_forever/src/_arch/aarch64/cpu/boot.s
93+
+++ 02_runtime_init/src/_arch/aarch64/cpu/boot.s
94+
@@ -3,6 +3,24 @@
95+
// Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
96+
97+
//--------------------------------------------------------------------------------------------------
98+
+// Definitions
99+
+//--------------------------------------------------------------------------------------------------
100+
+
101+
+// Load the address of a symbol into a register, PC-relative.
102+
+//
103+
+// The symbol must lie within +/- 4 GiB of the Program Counter.
104+
+//
105+
+// # Resources
106+
+//
107+
+// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html
108+
+.macro ADR_REL register, symbol
109+
+ adrp \register, \symbol
110+
+ add \register, \register, #:lo12:\symbol
111+
+.endm
112+
+
113+
+.equ _core_id_mask, 0b11
114+
+
115+
+//--------------------------------------------------------------------------------------------------
116+
// Public Code
117+
//--------------------------------------------------------------------------------------------------
118+
.section .text._start
119+
@@ -11,6 +29,34 @@
120+
// fn _start()
121+
//------------------------------------------------------------------------------
122+
_start:
123+
+ // Only proceed on the boot core. Park it otherwise.
124+
+ mrs x1, MPIDR_EL1
125+
+ and x1, x1, _core_id_mask
126+
+ ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
127+
+ cmp x1, x2
128+
+ b.ne .L_parking_loop
129+
+
130+
+ // If execution reaches here, it is the boot core.
131+
+
132+
+ // Initialize DRAM.
133+
+ ADR_REL x0, __bss_start
134+
+ ADR_REL x1, __bss_end_exclusive
135+
+
136+
+.L_bss_init_loop:
137+
+ cmp x0, x1
138+
+ b.eq .L_prepare_rust
139+
+ stp xzr, xzr, [x0], #16
140+
+ b .L_bss_init_loop
141+
+
142+
+ // Prepare the jump to Rust code.
143+
+.L_prepare_rust:
144+
+ // Set the stack pointer.
145+
+ ADR_REL x0, __boot_core_stack_end_exclusive
146+
+ mov sp, x0
147+
+
148+
+ // Jump to Rust code.
149+
+ b _start_rust
150+
+
151+
// Infinitely wait for events (aka "park the core").
152+
.L_parking_loop:
153+
wfe
154+
155+
diff -uNr 01_wait_forever/src/_arch/aarch64/cpu.rs 02_runtime_init/src/_arch/aarch64/cpu.rs
156+
--- 01_wait_forever/src/_arch/aarch64/cpu.rs
157+
+++ 02_runtime_init/src/_arch/aarch64/cpu.rs
158+
@@ -0,0 +1,26 @@
159+
+// SPDX-License-Identifier: MIT OR Apache-2.0
160+
+//
161+
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
162+
+
163+
+//! Architectural processor code.
164+
+//!
165+
+//! # Orientation
166+
+//!
167+
+//! Since arch modules are imported into generic modules using the path attribute, the path of this
168+
+//! file is:
169+
+//!
170+
+//! crate::cpu::arch_cpu
171+
+
172+
+use cortex_a::asm;
173+
+
174+
+//--------------------------------------------------------------------------------------------------
175+
+// Public Code
176+
+//--------------------------------------------------------------------------------------------------
177+
+
178+
+/// Pause execution on the core.
179+
+#[inline(always)]
180+
+pub fn wait_forever() -> ! {
181+
+ loop {
182+
+ asm::wfe()
183+
+ }
184+
+}
185+
186+
diff -uNr 01_wait_forever/src/bsp/raspberrypi/cpu.rs 02_runtime_init/src/bsp/raspberrypi/cpu.rs
187+
--- 01_wait_forever/src/bsp/raspberrypi/cpu.rs
188+
+++ 02_runtime_init/src/bsp/raspberrypi/cpu.rs
189+
@@ -0,0 +1,14 @@
190+
+// SPDX-License-Identifier: MIT OR Apache-2.0
191+
+//
192+
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
193+
+
194+
+//! BSP Processor code.
195+
+
196+
+//--------------------------------------------------------------------------------------------------
197+
+// Public Definitions
198+
+//--------------------------------------------------------------------------------------------------
199+
+
200+
+/// Used by `arch` code to find the early boot core.
201+
+#[no_mangle]
202+
+#[link_section = ".text._start_arguments"]
203+
+pub static BOOT_CORE_ID: u64 = 0;
204+
205+
diff -uNr 01_wait_forever/src/bsp/raspberrypi/link.ld 02_runtime_init/src/bsp/raspberrypi/link.ld
206+
--- 01_wait_forever/src/bsp/raspberrypi/link.ld
207+
+++ 02_runtime_init/src/bsp/raspberrypi/link.ld
208+
@@ -3,6 +3,8 @@
209+
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
210+
*/
211+
212+
+__rpi_phys_dram_start_addr = 0;
213+
+
214+
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
215+
__rpi_phys_binary_load_addr = 0x80000;
216+
217+
@@ -13,21 +15,58 @@
218+
* 4 == R
219+
* 5 == RX
220+
* 6 == RW
221+
+ *
222+
+ * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
223+
+ * It doesn't mean all of them need actually be loaded.
224+
*/
225+
PHDRS
226+
{
227+
- segment_code PT_LOAD FLAGS(5);
228+
+ segment_boot_core_stack PT_LOAD FLAGS(6);
229+
+ segment_code PT_LOAD FLAGS(5);
230+
+ segment_data PT_LOAD FLAGS(6);
231+
}
232+
233+
SECTIONS
234+
{
235+
- . = __rpi_phys_binary_load_addr;
236+
+ . = __rpi_phys_dram_start_addr;
237+
+
238+
+ /***********************************************************************************************
239+
+ * Boot Core Stack
240+
+ ***********************************************************************************************/
241+
+ .boot_core_stack (NOLOAD) :
242+
+ {
243+
+ /* ^ */
244+
+ /* | stack */
245+
+ . += __rpi_phys_binary_load_addr; /* | growth */
246+
+ /* | direction */
247+
+ __boot_core_stack_end_exclusive = .; /* | */
248+
+ } :segment_boot_core_stack
249+
250+
/***********************************************************************************************
251+
- * Code
252+
+ * Code + RO Data + Global Offset Table
253+
***********************************************************************************************/
254+
.text :
255+
{
256+
KEEP(*(.text._start))
257+
+ *(.text._start_arguments) /* Constants (or statics in Rust speak) read by _start(). */
258+
+ *(.text._start_rust) /* The Rust entry point */
259+
+ *(.text*) /* Everything else */
260+
} :segment_code
261+
+
262+
+ .rodata : ALIGN(8) { *(.rodata*) } :segment_code
263+
+ .got : ALIGN(8) { *(.got) } :segment_code
264+
+
265+
+ /***********************************************************************************************
266+
+ * Data + BSS
267+
+ ***********************************************************************************************/
268+
+ .data : { *(.data*) } :segment_data
269+
+
270+
+ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
271+
+ .bss (NOLOAD) : ALIGN(16)
272+
+ {
273+
+ __bss_start = .;
274+
+ *(.bss*);
275+
+ . = ALIGN(16);
276+
+ __bss_end_exclusive = .;
277+
+ } :segment_data
278+
}
279+
280+
diff -uNr 01_wait_forever/src/bsp/raspberrypi.rs 02_runtime_init/src/bsp/raspberrypi.rs
281+
--- 01_wait_forever/src/bsp/raspberrypi.rs
282+
+++ 02_runtime_init/src/bsp/raspberrypi.rs
283+
@@ -4,4 +4,4 @@
284+
285+
//! Top-level BSP file for the Raspberry Pi 3 and 4.
286+
287+
-// Coming soon.
288+
+pub mod cpu;
289+
290+
diff -uNr 01_wait_forever/src/cpu.rs 02_runtime_init/src/cpu.rs
291+
--- 01_wait_forever/src/cpu.rs
292+
+++ 02_runtime_init/src/cpu.rs
293+
@@ -4,4 +4,13 @@
294+
295+
//! Processor code.
296+
297+
+#[cfg(target_arch = "aarch64")]
298+
+#[path = "_arch/aarch64/cpu.rs"]
299+
+mod arch_cpu;
300+
+
301+
mod boot;
302+
+
303+
+//--------------------------------------------------------------------------------------------------
304+
+// Architectural Public Reexports
305+
+//--------------------------------------------------------------------------------------------------
306+
+pub use arch_cpu::wait_forever;
307+
308+
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
309+
--- 01_wait_forever/src/main.rs
310+
+++ 02_runtime_init/src/main.rs
311+
@@ -102,6 +102,7 @@
312+
//!
313+
//! 1. The kernel's entry point is the function `cpu::boot::arch_boot::_start()`.
314+
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`.
315+
+//! 2. Once finished with architectural setup, the arch code calls `kernel_init()`.
316+
317+
#![no_main]
318+
#![no_std]
319+
@@ -110,4 +111,11 @@
320+
mod cpu;
321+
mod panic_wait;
322+
323+
-// Kernel code coming next tutorial.
324+
+/// Early init code.
325+
+///
326+
+/// # Safety
327+
+///
328+
+/// - Only a single core must be active and running this function.
329+
+unsafe fn kernel_init() -> ! {
330+
+ panic!()
331+
+}
332+
333+
diff -uNr 01_wait_forever/src/panic_wait.rs 02_runtime_init/src/panic_wait.rs
334+
--- 01_wait_forever/src/panic_wait.rs
335+
+++ 02_runtime_init/src/panic_wait.rs
336+
@@ -4,9 +4,10 @@
337+
338+
//! A panic handler that infinitely waits.
339+
340+
+use crate::cpu;
341+
use core::panic::PanicInfo;
342+
343+
#[panic_handler]
344+
fn panic(_info: &PanicInfo) -> ! {
345+
- unimplemented!()
346+
+ cpu::wait_forever()
347+
}
348+
```

0 commit comments

Comments
 (0)