From a6be5b34ad621ab9425bb0b8913f99fcc525eba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=B0=7Ezanez?= <51524324+zanezhub@users.noreply.github.com> Date: Fri, 1 Apr 2022 01:14:44 -0600 Subject: [PATCH] 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 Co-authored-by: Andre Richter Co-authored-by: Diego Barrios Romero --- 01_wait_forever/README.ES.md | 55 ++++++ 02_runtime_init/README.ES.md | 348 +++++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 01_wait_forever/README.ES.md create mode 100644 02_runtime_init/README.ES.md diff --git a/01_wait_forever/README.ES.md b/01_wait_forever/README.ES.md new file mode 100644 index 00000000..5244372a --- /dev/null +++ b/01_wait_forever/README.ES.md @@ -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 +``` diff --git a/02_runtime_init/README.ES.md b/02_runtime_init/README.ES.md new file mode 100644 index 00000000..6a5b3974 --- /dev/null +++ b/02_runtime_init/README.ES.md @@ -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 "] + 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 + + //-------------------------------------------------------------------------------------------------- ++// 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 ++ ++//! 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 ++ ++//! 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 + */ + ++__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() + } +```