README.ES.md -> 01 & 02 (#150)
* README.ES.md I added a spanish translation for the README.md file, and modified the README.md to add my github profile and to add the link to README.ES.md file * Slightly reorganize translation overview * README.ES.md These changes are in response to PR comments * Update README.ES.md * README.ES.md -> 00_before_we_start * Updating README.ES.md I corrected a few mistakes in both README.ES.md files. * README.ES.md for 00 These changes are in response to PR comments * README.ES.md -> 01_wait_forever * README.ES.md -> 02_runtime_init * README.md for 01 & 02 with corrections/improvements * Update 01_wait_forever/README.ES.md * Update 02_runtime_init/README.ES.md Co-authored-by: zanez <zanez@protonmail.com> Co-authored-by: Andre Richter <andre-richter@users.noreply.github.com> Co-authored-by: Diego Barrios Romero <eldruin@gmail.com>pull/151/head
parent
722e8b7232
commit
a6be5b34ad
@ -0,0 +1,55 @@
|
||||
# Tutorial 01 - Esperar infinitamente
|
||||
|
||||
## tl;dr
|
||||
|
||||
* Se configura la estructura que tiene el proyecto.
|
||||
|
||||
* Se ejecuta una pequeño código hecho en ensamblador que tiene como función detener todos los núcleos del procesador que están ejecutando el kernel.
|
||||
|
||||
## Compilar
|
||||
|
||||
* El archivo `Makefile` permite ejecutar:
|
||||
|
||||
* `doc`: Genera la documentación.
|
||||
|
||||
* `qemu`: Ejecutar el kernel en QEMU.
|
||||
|
||||
* `clippy`: Analiza el código y sugiere mejoras.
|
||||
|
||||
* `clean`: Elimina todos los archivos generados durante la compilación, etc.
|
||||
|
||||
* `readelf`: Inspecciona el archivo `ELF` de salida.
|
||||
|
||||
* `objdump`: Inspecciona el ensamblador.
|
||||
|
||||
* `nm`: Inspecciona los símbolos.
|
||||
|
||||
## Código a revisar
|
||||
|
||||
* El script para enlazado específico para la `BSP` llamado `link.ld`.
|
||||
|
||||
* Carga la dirección en `0x8_0000`.
|
||||
|
||||
* Solo la sección `.text`.
|
||||
|
||||
* `main.rs`: [Atributos internos](https://doc.rust-lang.org/reference/attributes.html) importantes:
|
||||
|
||||
* `#![no_std]`, `#![no_main]`.
|
||||
|
||||
* `boot.s`: La función de ensamblador `_start()` que inicia `wfe` (Wait For Event / Esperar Hasta Un Evento), detiene todos los núcleos del procesador que están ejecutando `_start()`.
|
||||
|
||||
* Tenemos que definir una función que funcione como `#[panic_handler]` (manejador de pánico) para que el compilador no nos cause problemas.
|
||||
|
||||
* Hazla `unimplemented!()` porque se eliminará ya que no está siendo usada.
|
||||
|
||||
## Pruébalo
|
||||
|
||||
Dentro de la carpeta del proyecto, ejecuta a QEMU y mira el núcleo del procesador ejecutando `wfe` en bucle:
|
||||
|
||||
```
|
||||
$ make qemu
|
||||
[...]
|
||||
IN:
|
||||
0x00080000: d503205f wfe
|
||||
0x00080004: 17ffffff b #0x80000
|
||||
```
|
@ -0,0 +1,348 @@
|
||||
# Tutorial 02 - Inicialización del `runtime`
|
||||
|
||||
## tl;dr
|
||||
|
||||
* Extendimos la funcionalidad de `boot.s` para que sea capaz de llamar código Rust por primera vez. Antes de que el cambio a Rust ocurra, se realizan algunos trabajos de inicialización del `runtime` (soporte para ejecución de código).
|
||||
* El código Rust que es llamado solo pausa la ejecución con una llamada a `panic!()`.
|
||||
* Ejecuta `make qemu` de nuevo para que puedas ver el código adicional en acción.
|
||||
|
||||
## Adiciones importantes
|
||||
|
||||
* Adiciones importantes al script `link.ld`:
|
||||
|
||||
* Nuevas secciones: `.rodata`, `.got`, `.data`, `.bss`.
|
||||
|
||||
* Un lugar totalmente dedicado a enlazar argumentos de tiempo de arranque (boot-time) que necesitan estar listos cuando se llame a `_start()`.
|
||||
|
||||
* `_start()` en `_arch/__arch_name__/cpu/boot.s`:
|
||||
|
||||
1. Para todos los núcleos expecto el núcleo 0.
|
||||
|
||||
2. Inicializa la [`DRAM`](https://es.wikipedia.org/wiki/DRAM) poniendo a cero la sección [`.bss`](https://en.wikipedia.org/wiki/.bss).
|
||||
|
||||
3. Configura el `stack pointer` (puntero a la memoria [pila](https://es.wikipedia.org/wiki/Pila_(inform%C3%A1tica))).
|
||||
|
||||
4. Salta hacia la función `_start_rust()`, definida en `arch/__arch_name__/cpu/boot.rs`.
|
||||
|
||||
* `_start_rust()`:
|
||||
|
||||
* Llama a `kernel_init()`, que llama a `panic!()`, que al final también pone al núcleo 0 en pausa.
|
||||
|
||||
* La librería ahora usa el crate [cortex-a](https://github.com/rust-embedded/cortex-a), que nos da abstracciones sin coste y envuelve las partes que hacen uso de un `unsafe` (partes con código que no es seguro y podría causar errores) cuando se trabaja directamente con los recursos del procesador.
|
||||
|
||||
* Lo puedes ver en acción en `_arch/__arch_name__/cpu.rs`.
|
||||
|
||||
## Diferencia con el archivo anterior
|
||||
|
||||
```diff
|
||||
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 = "2021"
|
||||
|
||||
@@ -21,3 +21,7 @@
|
||||
##--------------------------------------------------------------------------------------------------
|
||||
|
||||
[dependencies]
|
||||
+
|
||||
+# Platform specific dependencies
|
||||
+[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
+cortex-a = { version = "7.x.x" }
|
||||
|
||||
diff -uNr 01_wait_forever/Makefile 02_runtime_init/Makefile
|
||||
--- 01_wait_forever/Makefile
|
||||
+++ 02_runtime_init/Makefile
|
||||
@@ -153,6 +153,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.
|
||||
core::arch::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-2022 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-2022 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-2022 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
|
||||
@@ -3,6 +3,8 @@
|
||||
* Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
|
||||
*/
|
||||
|
||||
+__rpi_phys_dram_start_addr = 0;
|
||||
+
|
||||
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
|
||||
__rpi_phys_binary_load_addr = 0x80000;
|
||||
|
||||
@@ -13,21 +15,58 @@
|
||||
* 4 == R
|
||||
* 5 == RX
|
||||
* 6 == RW
|
||||
+ *
|
||||
+ * Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
|
||||
+ * It doesn't mean all of them need actually be loaded.
|
||||
*/
|
||||
PHDRS
|
||||
{
|
||||
- segment_code PT_LOAD FLAGS(5);
|
||||
+ segment_boot_core_stack PT_LOAD FLAGS(6);
|
||||
+ segment_code PT_LOAD FLAGS(5);
|
||||
+ segment_data PT_LOAD FLAGS(6);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
- . = __rpi_phys_binary_load_addr;
|
||||
+ . = __rpi_phys_dram_start_addr;
|
||||
+
|
||||
+ /***********************************************************************************************
|
||||
+ * Boot Core Stack
|
||||
+ ***********************************************************************************************/
|
||||
+ .boot_core_stack (NOLOAD) :
|
||||
+ {
|
||||
+ /* ^ */
|
||||
+ /* | stack */
|
||||
+ . += __rpi_phys_binary_load_addr; /* | growth */
|
||||
+ /* | direction */
|
||||
+ __boot_core_stack_end_exclusive = .; /* | */
|
||||
+ } :segment_boot_core_stack
|
||||
|
||||
/***********************************************************************************************
|
||||
- * 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_code
|
||||
+
|
||||
+ .rodata : ALIGN(8) { *(.rodata*) } :segment_code
|
||||
+ .got : ALIGN(8) { *(.got) } :segment_code
|
||||
+
|
||||
+ /***********************************************************************************************
|
||||
+ * Data + BSS
|
||||
+ ***********************************************************************************************/
|
||||
+ .data : { *(.data*) } :segment_data
|
||||
+
|
||||
+ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
|
||||
+ .bss (NOLOAD) : ALIGN(16)
|
||||
+ {
|
||||
+ __bss_start = .;
|
||||
+ *(.bss*);
|
||||
+ . = ALIGN(16);
|
||||
+ __bss_end_exclusive = .;
|
||||
+ } :segment_data
|
||||
}
|
||||
|
||||
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,6 +102,7 @@
|
||||
//!
|
||||
//! 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()`.
|
||||
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
@@ -110,4 +111,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()
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue