diff --git a/02_runtime_init/README.CN.md b/02_runtime_init/README.CN.md index 51c63793..46c52467 100644 --- a/02_runtime_init/README.CN.md +++ b/02_runtime_init/README.CN.md @@ -19,302 +19,5 @@ [bss]: https://en.wikipedia.org/wiki/.bss ## 相比之前的变化(diff) -```diff -diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml ---- 01_wait_forever/Cargo.toml -+++ 02_runtime_init/Cargo.toml -@@ -4,6 +4,9 @@ - authors = ["Andre Richter "] - edition = "2018" - -+[profile.release] -+lto = true -+ - # The features section is used to select the target board. - [features] - default = [] - -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 -@@ -7,5 +7,15 @@ - .global _start - - _start: --1: wfe // Wait for event -- b 1b // In case an event happened, jump back to 1 -+ mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register -+ and x1, x1, #3 // Clear all bits except [1:0], which hold core id -+ cbz x1, 2f // Jump to label 2 if we are core 0 -+1: wfe // Wait for event -+ b 1b // In case an event happened, jump back to 1 -+2: // If we are here, we are core0 -+ ldr x1, =_start // Load address of function "_start()" -+ mov sp, x1 // Set start of stack to before our code, aka first -+ // address before "_start()" -+ bl runtime_init // Jump to the "runtime_init()" kernel function -+ b 1b // We should never reach here. But just in case, -+ // park this core aswell - -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,30 @@ -+// 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 -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Pause execution on the core. -+#[inline(always)] -+pub fn wait_forever() -> ! { -+ unsafe { -+ loop { -+ #[rustfmt::skip] -+ asm!( -+ "wfe", -+ options(nomem, nostack, preserves_flags) -+ ); -+ } -+ } -+} - -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 -@@ -13,5 +13,27 @@ - *(.text._start) *(.text*) - } - -+ .rodata : -+ { -+ *(.rodata*) -+ } -+ -+ .data : -+ { -+ *(.data*) -+ } -+ -+ /* Section is zeroed in u64 chunks, align start and end to 8 bytes */ -+ .bss ALIGN(8): -+ { -+ __bss_start = .; -+ *(.bss*); -+ . = ALIGN(8); -+ -+ /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */ -+ . += 8; -+ __bss_end_inclusive = . - 8; -+ } -+ - /DISCARD/ : { *(.comment*) } - } - -diff -uNr 01_wait_forever/src/bsp/raspberrypi/memory.rs 02_runtime_init/src/bsp/raspberrypi/memory.rs ---- 01_wait_forever/src/bsp/raspberrypi/memory.rs -+++ 02_runtime_init/src/bsp/raspberrypi/memory.rs -@@ -0,0 +1,37 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! BSP Memory Management. -+ -+use core::{cell::UnsafeCell, ops::RangeInclusive}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+// Symbols from the linker script. -+extern "Rust" { -+ static __bss_start: UnsafeCell; -+ static __bss_end_inclusive: UnsafeCell; -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Return the inclusive range spanning the .bss section. -+/// -+/// # Safety -+/// -+/// - Values are provided by the linker script and must be trusted as-is. -+/// - The linker-provided addresses must be u64 aligned. -+pub fn bss_range_inclusive() -> RangeInclusive<*mut u64> { -+ let range; -+ unsafe { -+ range = RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get()); -+ } -+ assert!(!range.is_empty()); -+ -+ range -+} - -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 memory; - -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.rs`. -+//! 2. Once finished with architectural setup, the arch code calls [`runtime_init::runtime_init()`]. - //! - //! [`cpu::boot::arch_boot::_start()`]: cpu/boot/arch_boot/fn._start.html - -@@ -112,6 +113,15 @@ - - mod bsp; - mod cpu; -+mod memory; - mod panic_wait; -+mod runtime_init; - --// 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/memory.rs 02_runtime_init/src/memory.rs ---- 01_wait_forever/src/memory.rs -+++ 02_runtime_init/src/memory.rs -@@ -0,0 +1,30 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Memory Management. -+ -+use core::ops::RangeInclusive; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Zero out an inclusive memory range. -+/// -+/// # Safety -+/// -+/// - `range.start` and `range.end` must be valid. -+/// - `range.start` and `range.end` must be `T` aligned. -+pub unsafe fn zero_volatile(range: RangeInclusive<*mut T>) -+where -+ T: From, -+{ -+ let mut ptr = *range.start(); -+ let end_inclusive = *range.end(); -+ -+ while ptr <= end_inclusive { -+ core::ptr::write_volatile(ptr, T::from(0)); -+ ptr = ptr.offset(1); -+ } -+} - -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() - } - -diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.rs ---- 01_wait_forever/src/runtime_init.rs -+++ 02_runtime_init/src/runtime_init.rs -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Rust runtime initialization code. -+ -+use crate::{bsp, memory}; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Zero out the .bss section. -+/// -+/// # Safety -+/// -+/// - Must only be called pre `kernel_init()`. -+#[inline(always)] -+unsafe fn zero_bss() { -+ memory::zero_volatile(bsp::memory::bss_range_inclusive()); -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel -+/// init code. -+/// -+/// # Safety -+/// -+/// - Only a single core must be active and running this function. -+#[no_mangle] -+pub unsafe fn runtime_init() -> ! { -+ zero_bss(); -+ -+ crate::kernel_init() -+} - -``` +Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. diff --git a/02_runtime_init/README.ES.md b/02_runtime_init/README.ES.md index 6a5b3974..79c4c2b4 100644 --- a/02_runtime_init/README.ES.md +++ b/02_runtime_init/README.ES.md @@ -9,340 +9,29 @@ ## 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() - } -``` +Please check [the english version](README.md#diff-to-previous), which is kept up-to-date. diff --git a/03_hacky_hello_world/README.ES.md b/03_hacky_hello_world/README.ES.md index f52b226e..eafa3c21 100644 --- a/03_hacky_hello_world/README.ES.md +++ b/03_hacky_hello_world/README.ES.md @@ -31,292 +31,15 @@ Kernel panic: Stopping here. * *Hacky:* Solución torpe o poco elegante para un problema. * *Debugging:* Proceso para identificar y corregir errores de programación. - + * *printf debugging:* Usado para describir el trabajo de depuración (*debugging*) poniendo comandos que dan una salida en consola, como el de "printf", en diferentes lugares del programa; observando la información y tratando de deducir qué está mal en el programa basándose en la información que nos dan nuestros comandos. * *Traits:* Un *trait* le hace saber al compilador de Rust acerca de una funcionalidad que tiene un tipo de dato particular y que puede compartir con otros tipos de datos. - + > NOTA: Los *traits* son similares a una característica que se le conoce comúnmente como *interfaces* en otros lenguajes, aunque con algunas diferencias. - + Si deseas aprender más acerca de esto, por favor lee este capítulo del libro de Rust: [Traits: Defining Shared Behavior - The Rust Programming Language](https://doc.rust-lang.org/book/ch10-02-traits.html) ## Diferencias con el archivo anterior -```diff -diff -uNr 02_runtime_init/Cargo.toml 03_hacky_hello_world/Cargo.toml ---- 02_runtime_init/Cargo.toml -+++ 03_hacky_hello_world/Cargo.toml -@@ -1,6 +1,6 @@ - [package] - name = "mingo" --version = "0.2.0" -+version = "0.3.0" - authors = ["Andre Richter "] - edition = "2021" - - -diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile ---- 02_runtime_init/Makefile -+++ 03_hacky_hello_world/Makefile -@@ -24,7 +24,7 @@ - KERNEL_BIN = kernel8.img - QEMU_BINARY = qemu-system-aarch64 - QEMU_MACHINE_TYPE = raspi3 -- QEMU_RELEASE_ARGS = -d in_asm -display none -+ QEMU_RELEASE_ARGS = -serial stdio -display none - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf -@@ -35,7 +35,7 @@ - KERNEL_BIN = kernel8.img - QEMU_BINARY = qemu-system-aarch64 - QEMU_MACHINE_TYPE = -- QEMU_RELEASE_ARGS = -d in_asm -display none -+ QEMU_RELEASE_ARGS = -serial stdio -display none - OBJDUMP_BINARY = aarch64-none-elf-objdump - NM_BINARY = aarch64-none-elf-nm - READELF_BINARY = aarch64-none-elf-readelf -@@ -71,17 +71,20 @@ - --strip-all \ - -O binary - --EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -+EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -+EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb - - ##------------------------------------------------------------------------------ - ## Dockerization - ##------------------------------------------------------------------------------ --DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial --DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -+DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial -+DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -+DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common - - # DOCKER_IMAGE defined in include file (see top of this file). - DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) - DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE) -+DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE) - - - -@@ -169,3 +172,28 @@ - ##------------------------------------------------------------------------------ - check: - @RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json -+ -+ -+ -+##-------------------------------------------------------------------------------------------------- -+## Testing targets -+##-------------------------------------------------------------------------------------------------- -+.PHONY: test test_boot -+ -+ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board. -+ -+test_boot test : -+ $(call colorecho, "\n$(QEMU_MISSING_STRING)") -+ -+else # QEMU is supported. -+ -+##------------------------------------------------------------------------------ -+## Run boot test -+##------------------------------------------------------------------------------ -+test_boot: $(KERNEL_BIN) -+ $(call colorecho, "\nBoot test - $(BSP)") -+ @$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN) -+ -+test: test_boot -+ -+endif - -diff -uNr 02_runtime_init/src/bsp/raspberrypi/console.rs 03_hacky_hello_world/src/bsp/raspberrypi/console.rs ---- 02_runtime_init/src/bsp/raspberrypi/console.rs -+++ 03_hacky_hello_world/src/bsp/raspberrypi/console.rs -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! BSP console facilities. -+ -+use crate::console; -+use core::fmt; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+/// A mystical, magical device for generating QEMU output out of the void. -+struct QEMUOutput; -+ -+//-------------------------------------------------------------------------------------------------- -+// Private Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are -+/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`, -+/// we get `write_fmt()` automatically. -+/// -+/// See [`src/print.rs`]. -+/// -+/// [`src/print.rs`]: ../../print/index.html -+impl fmt::Write for QEMUOutput { -+ fn write_str(&mut self, s: &str) -> fmt::Result { -+ for c in s.chars() { -+ unsafe { -+ core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8); -+ } -+ } -+ -+ Ok(()) -+ } -+} -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+/// Return a reference to the console. -+pub fn console() -> impl console::interface::Write { -+ QEMUOutput {} -+} - -diff -uNr 02_runtime_init/src/bsp/raspberrypi.rs 03_hacky_hello_world/src/bsp/raspberrypi.rs ---- 02_runtime_init/src/bsp/raspberrypi.rs -+++ 03_hacky_hello_world/src/bsp/raspberrypi.rs -@@ -4,4 +4,5 @@ - - //! Top-level BSP file for the Raspberry Pi 3 and 4. - -+pub mod console; - pub mod cpu; - -diff -uNr 02_runtime_init/src/console.rs 03_hacky_hello_world/src/console.rs ---- 02_runtime_init/src/console.rs -+++ 03_hacky_hello_world/src/console.rs -@@ -0,0 +1,19 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! System console. -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Definitions -+//-------------------------------------------------------------------------------------------------- -+ -+/// Console interfaces. -+pub mod interface { -+ /// Console write functions. -+ /// -+ /// `core::fmt::Write` is exactly what we need for now. Re-export it here because -+ /// implementing `console::Write` gives a better hint to the reader about the -+ /// intention. -+ pub use core::fmt::Write; -+} - -diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs ---- 02_runtime_init/src/main.rs -+++ 03_hacky_hello_world/src/main.rs -@@ -104,12 +104,16 @@ - //! - It is implemented in `src/_arch/__arch_name__/cpu/boot.s`. - //! 2. Once finished with architectural setup, the arch code calls `kernel_init()`. - -+#![feature(format_args_nl)] -+#![feature(panic_info_message)] - #![no_main] - #![no_std] - - mod bsp; -+mod console; - mod cpu; - mod panic_wait; -+mod print; - - /// Early init code. - /// -@@ -117,5 +121,7 @@ - /// - /// - Only a single core must be active and running this function. - unsafe fn kernel_init() -> ! { -- panic!() -+ println!("[0] Hello from Rust!"); -+ -+ panic!("Stopping here.") - } - -diff -uNr 02_runtime_init/src/panic_wait.rs 03_hacky_hello_world/src/panic_wait.rs ---- 02_runtime_init/src/panic_wait.rs -+++ 03_hacky_hello_world/src/panic_wait.rs -@@ -4,10 +4,16 @@ - - //! A panic handler that infinitely waits. - --use crate::cpu; -+use crate::{cpu, println}; - use core::panic::PanicInfo; - - #[panic_handler] --fn panic(_info: &PanicInfo) -> ! { -+fn panic(info: &PanicInfo) -> ! { -+ if let Some(args) = info.message() { -+ println!("\nKernel panic: {}", args); -+ } else { -+ println!("\nKernel panic!"); -+ } -+ - cpu::wait_forever() - } - -diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs ---- 02_runtime_init/src/print.rs -+++ 03_hacky_hello_world/src/print.rs -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: MIT OR Apache-2.0 -+// -+// Copyright (c) 2018-2022 Andre Richter -+ -+//! Printing. -+ -+use crate::{bsp, console}; -+use core::fmt; -+ -+//-------------------------------------------------------------------------------------------------- -+// Public Code -+//-------------------------------------------------------------------------------------------------- -+ -+#[doc(hidden)] -+pub fn _print(args: fmt::Arguments) { -+ use console::interface::Write; -+ -+ bsp::console::console().write_fmt(args).unwrap(); -+} -+ -+/// Prints without a newline. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! print { -+ ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*))); -+} -+ -+/// Prints with a newline. -+/// -+/// Carbon copy from -+#[macro_export] -+macro_rules! println { -+ () => ($crate::print!("\n")); -+ ($($arg:tt)*) => ({ -+ $crate::print::_print(format_args_nl!($($arg)*)); -+ }) -+} - -diff -uNr 02_runtime_init/tests/boot_test_string.rb 03_hacky_hello_world/tests/boot_test_string.rb ---- 02_runtime_init/tests/boot_test_string.rb -+++ 03_hacky_hello_world/tests/boot_test_string.rb -@@ -0,0 +1,3 @@ -+# frozen_string_literal: true -+ -+EXPECTED_PRINT = 'Stopping here' -``` +Please check [the english version](README.md#diff-to-previous), which is kept up-to-date.