Add first bunch of README stubs
parent
f9020bbb03
commit
651097d55e
@ -0,0 +1,31 @@
|
||||
# Tutorial 01 - Wait Forever
|
||||
|
||||
## tl;dr
|
||||
|
||||
Project skeleton is set up; Code just halts all CPU cores.
|
||||
|
||||
- Toolchain: `cargo xbuild` tools (`xrustc`, `xclippy`) and the
|
||||
`aarch64-unknown-none` target are used for building `AArch64` bare-metal code.
|
||||
- `Makefile` targets:
|
||||
- `doc`: Generate documentation.
|
||||
- `qemu`: Run the `kernel` in QEMU
|
||||
- `clippy`
|
||||
- `clean`
|
||||
- `readelf`: Inspect the `ELF` output.
|
||||
- `objdump`: Inspect the assembly.
|
||||
- `nm`: Inspect the symbols.
|
||||
- Code is organized into `kernel` and `BSP` (Board Support Package) parts.
|
||||
- Conditional compilation includes a `BSP` according to user-supplied
|
||||
arguments.
|
||||
- Custom `link.ld` linker script.
|
||||
- Load address at `0x80_000`
|
||||
- Only `.text` section.
|
||||
- `main.rs`: Important [inner attributes]:
|
||||
- `#![no_std]`, `#![no_main]`
|
||||
- Assembly `_start()` function that executes `wfe` (Wait For Event), halting all
|
||||
cores that are executing `_start()`.
|
||||
- We (have to) define a `#[panic_handler]` function.
|
||||
- Done in `BSP` code.
|
||||
- Just executes `wfe`.
|
||||
|
||||
[inner attributes]: https://doc.rust-lang.org/reference/attributes.html
|
@ -0,0 +1,129 @@
|
||||
# Tutorial 02 - Runtime Init
|
||||
|
||||
## tl;dr
|
||||
|
||||
We are calling into Rust code for the first time.
|
||||
|
||||
- More sections in linker script:
|
||||
- `.rodata`, `.data`
|
||||
- `.bss`
|
||||
- `_start()`:
|
||||
- Halt core if core != `core0`.
|
||||
- `core0` jumps to `init()` Rust function.
|
||||
- `init()`
|
||||
- Zeros the `.bss` section.
|
||||
- Calls `kernel_entry()`, which calls `panic!()`, which eventually halts
|
||||
`core0` as well.
|
||||
|
||||
## Diff to previous
|
||||
```diff
|
||||
|
||||
diff -uNr 01_wait_forever/Cargo.toml 02_runtime_init/Cargo.toml
|
||||
--- 01_wait_forever/Cargo.toml 2019-09-23 15:09:10.919233495 +0200
|
||||
+++ 02_runtime_init/Cargo.toml 2019-09-23 15:10:15.775036819 +0200
|
||||
@@ -13,4 +13,4 @@
|
||||
bsp_rpi3 = []
|
||||
|
||||
[dependencies]
|
||||
-
|
||||
+r0 = "0.2.2"
|
||||
|
||||
diff -uNr 01_wait_forever/src/bsp/rpi3/link.ld 02_runtime_init/src/bsp/rpi3/link.ld
|
||||
--- 01_wait_forever/src/bsp/rpi3/link.ld 2019-09-23 15:09:10.919233495 +0200
|
||||
+++ 02_runtime_init/src/bsp/rpi3/link.ld 2019-09-23 15:10:15.767036845 +0200
|
||||
@@ -13,5 +13,23 @@
|
||||
*(.text)
|
||||
}
|
||||
|
||||
+ .rodata :
|
||||
+ {
|
||||
+ *(.rodata)
|
||||
+ }
|
||||
+
|
||||
+ .data :
|
||||
+ {
|
||||
+ *(.data)
|
||||
+ }
|
||||
+
|
||||
+ /* Align to 8 byte boundary */
|
||||
+ .bss ALIGN(8):
|
||||
+ {
|
||||
+ __bss_start = .;
|
||||
+ *(.bss);
|
||||
+ __bss_end = .;
|
||||
+ }
|
||||
+
|
||||
/DISCARD/ : { *(.comment) }
|
||||
}
|
||||
|
||||
diff -uNr 01_wait_forever/src/bsp/rpi3/start.S 02_runtime_init/src/bsp/rpi3/start.S
|
||||
--- 01_wait_forever/src/bsp/rpi3/start.S 2019-09-23 15:09:10.919233495 +0200
|
||||
+++ 02_runtime_init/src/bsp/rpi3/start.S 2019-09-23 15:10:15.767036845 +0200
|
||||
@@ -7,5 +7,15 @@
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
-1: wfe // Wait for event
|
||||
- b 1b // In case an event happend, 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 happend, 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 init // Jump to the "init()" kernel function
|
||||
+ b 1b // We should never reach here. But just in case,
|
||||
+ // park this core aswell
|
||||
|
||||
diff -uNr 01_wait_forever/src/main.rs 02_runtime_init/src/main.rs
|
||||
--- 01_wait_forever/src/main.rs 2019-09-24 22:57:44.947372097 +0200
|
||||
+++ 02_runtime_init/src/main.rs 2019-09-24 22:57:32.811412514 +0200
|
||||
@@ -16,4 +16,11 @@
|
||||
// `_start()` function, the first function to run.
|
||||
mod bsp;
|
||||
|
||||
-// Kernel code coming next tutorial.
|
||||
+// Afterwards, `BSP`'s early init code calls `runtime_init::init()` of this
|
||||
+// module, which on completion, jumps to `kernel_entry()`.
|
||||
+mod runtime_init;
|
||||
+
|
||||
+/// Entrypoint of the `kernel`.
|
||||
+fn kernel_entry() -> ! {
|
||||
+ panic!()
|
||||
+}
|
||||
|
||||
diff -uNr 01_wait_forever/src/runtime_init.rs 02_runtime_init/src/runtime_init.rs
|
||||
--- 01_wait_forever/src/runtime_init.rs 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ 02_runtime_init/src/runtime_init.rs 2019-09-24 22:32:25.569243801 +0200
|
||||
@@ -0,0 +1,27 @@
|
||||
+// SPDX-License-Identifier: MIT
|
||||
+//
|
||||
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
|
||||
+
|
||||
+//! Rust runtime initialization code.
|
||||
+
|
||||
+/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
|
||||
+/// then calls the kernel entry.
|
||||
+///
|
||||
+/// Called from BSP code.
|
||||
+///
|
||||
+/// # Safety
|
||||
+///
|
||||
+/// - Only a single core must be active and running this function.
|
||||
+#[no_mangle]
|
||||
+pub unsafe extern "C" fn init() -> ! {
|
||||
+ extern "C" {
|
||||
+ // Boundaries of the .bss section, provided by the linker script
|
||||
+ static mut __bss_start: u64;
|
||||
+ static mut __bss_end: u64;
|
||||
+ }
|
||||
+
|
||||
+ // Zero out the .bss section
|
||||
+ r0::zero_bss(&mut __bss_start, &mut __bss_end);
|
||||
+
|
||||
+ crate::kernel_entry()
|
||||
+}
|
||||
```
|
@ -0,0 +1,210 @@
|
||||
# Tutorial 03 - Hacky Hello World
|
||||
|
||||
## tl;dr
|
||||
|
||||
Introducing global `print!()` macros to enable "printf debugging" at the
|
||||
earliest; To keep tutorial length reasonable, printing function for now abuses a
|
||||
QEMU property and doesn't really use the RPi3's `UART`; Using real `UART` is
|
||||
enabled step-by-step in following tutorials.
|
||||
|
||||
- `interface.rs` is introduced:
|
||||
- Provides `Traits` for abstracting `kernel` from `BSP` code.
|
||||
- Panic handler `print!()`s supplied error messages.
|
||||
|
||||
## Diff to previous
|
||||
```diff
|
||||
|
||||
diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
|
||||
--- 02_runtime_init/Makefile 2019-09-23 15:10:43.906916928 +0200
|
||||
+++ 03_hacky_hello_world/Makefile 2019-09-23 15:11:53.602555646 +0200
|
||||
@@ -13,7 +13,7 @@
|
||||
OUTPUT = kernel8.img
|
||||
QEMU_BINARY = qemu-system-aarch64
|
||||
QEMU_MACHINE_TYPE = raspi3
|
||||
- QEMU_MISC_ARGS = -d in_asm
|
||||
+ QEMU_MISC_ARGS = -serial null -serial stdio
|
||||
LINKER_FILE = src/bsp/rpi3/link.ld
|
||||
RUSTC_MISC_ARGS = -C target-feature=-fp-armv8 -C target-cpu=cortex-a53
|
||||
endif
|
||||
|
||||
diff -uNr 02_runtime_init/src/bsp/rpi3/panic_wait.rs 03_hacky_hello_world/src/bsp/rpi3/panic_wait.rs
|
||||
--- 02_runtime_init/src/bsp/rpi3/panic_wait.rs 2019-09-23 15:10:15.767036845 +0200
|
||||
+++ 03_hacky_hello_world/src/bsp/rpi3/panic_wait.rs 2019-09-24 00:48:21.431980264 +0200
|
||||
@@ -4,10 +4,17 @@
|
||||
|
||||
//! A panic handler that infinitely waits.
|
||||
|
||||
+use crate::println;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[panic_handler]
|
||||
-fn panic(_info: &PanicInfo) -> ! {
|
||||
+fn panic(info: &PanicInfo) -> ! {
|
||||
+ if let Some(args) = info.message() {
|
||||
+ println!("{}", args);
|
||||
+ } else {
|
||||
+ println!("Kernel panic!");
|
||||
+ }
|
||||
+
|
||||
unsafe {
|
||||
loop {
|
||||
asm!("wfe" :::: "volatile")
|
||||
|
||||
diff -uNr 02_runtime_init/src/bsp/rpi3.rs 03_hacky_hello_world/src/bsp/rpi3.rs
|
||||
--- 02_runtime_init/src/bsp/rpi3.rs 2019-09-23 15:10:15.767036845 +0200
|
||||
+++ 03_hacky_hello_world/src/bsp/rpi3.rs 2019-09-24 22:34:35.220657927 +0200
|
||||
@@ -6,4 +6,38 @@
|
||||
|
||||
mod panic_wait;
|
||||
|
||||
+use crate::interface::console;
|
||||
+use core::fmt;
|
||||
+
|
||||
global_asm!(include_str!("rpi3/start.S"));
|
||||
+
|
||||
+/// A mystical, magical device for generating QEMU output out of the void.
|
||||
+struct QEMUOutput;
|
||||
+
|
||||
+/// Implementing `console::Write` enables usage of the `format_args!` macros,
|
||||
+/// which in turn are used to implement the `kernel`'s `print!` and `println!`
|
||||
+/// macros.
|
||||
+///
|
||||
+/// See [`src/print.rs`].
|
||||
+///
|
||||
+/// [`src/print.rs`]: ../../print/index.html
|
||||
+impl console::Write for QEMUOutput {
|
||||
+ fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
+ for c in s.chars() {
|
||||
+ unsafe {
|
||||
+ core::ptr::write_volatile(0x3F21_5040 as *mut u8, c as u8);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ Ok(())
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+////////////////////////////////////////////////////////////////////////////////
|
||||
+// Implementation of the kernel's BSP calls
|
||||
+////////////////////////////////////////////////////////////////////////////////
|
||||
+
|
||||
+/// Returns a ready-to-use `console::Write` implementation.
|
||||
+pub fn console() -> impl console::Write {
|
||||
+ QEMUOutput {}
|
||||
+}
|
||||
|
||||
diff -uNr 02_runtime_init/src/interface.rs 03_hacky_hello_world/src/interface.rs
|
||||
--- 02_runtime_init/src/interface.rs 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ 03_hacky_hello_world/src/interface.rs 2019-09-24 22:35:18.288465568 +0200
|
||||
@@ -0,0 +1,36 @@
|
||||
+// SPDX-License-Identifier: MIT
|
||||
+//
|
||||
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
|
||||
+
|
||||
+//! Trait definitions for coupling `kernel` and `BSP` code.
|
||||
+//!
|
||||
+//! ```
|
||||
+//! +-------------------+
|
||||
+//! | Interface (Trait) |
|
||||
+//! | |
|
||||
+//! +--+-------------+--+
|
||||
+//! ^ ^
|
||||
+//! | |
|
||||
+//! | |
|
||||
+//! +----------+--+ +--+----------+
|
||||
+//! | Kernel code | | BSP Code |
|
||||
+//! | | | |
|
||||
+//! +-------------+ +-------------+
|
||||
+//! ```
|
||||
+
|
||||
+/// System console operations.
|
||||
+pub mod console {
|
||||
+ /// Console write functions.
|
||||
+ ///
|
||||
+ /// `core::fmt::Write` is exactly what we need. Re-export it here because
|
||||
+ /// implementing `console::Write` gives a better hint to the reader about
|
||||
+ /// the intention.
|
||||
+ pub use core::fmt::Write;
|
||||
+
|
||||
+ /// Console read functions.
|
||||
+ pub trait Read {
|
||||
+ fn read_char(&mut self) -> char {
|
||||
+ ' '
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
|
||||
diff -uNr 02_runtime_init/src/main.rs 03_hacky_hello_world/src/main.rs
|
||||
--- 02_runtime_init/src/main.rs 2019-09-24 22:57:32.811412514 +0200
|
||||
+++ 03_hacky_hello_world/src/main.rs 2019-09-24 22:56:54.635538411 +0200
|
||||
@@ -6,9 +6,17 @@
|
||||
#![doc(html_logo_url = "https://git.io/JeGIp")]
|
||||
|
||||
//! The `kernel`
|
||||
+//!
|
||||
+//! The `kernel` is composed by glueing together hardware-specific Board Support
|
||||
+//! Package (`BSP`) code and hardware-agnostic `kernel` code through the
|
||||
+//! [`kernel::interface`] traits.
|
||||
+//!
|
||||
+//! [`kernel::interface`]: interface/index.html
|
||||
|
||||
#![feature(asm)]
|
||||
+#![feature(format_args_nl)]
|
||||
#![feature(global_asm)]
|
||||
+#![feature(panic_info_message)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
@@ -20,7 +28,12 @@
|
||||
// module, which on completion, jumps to `kernel_entry()`.
|
||||
mod runtime_init;
|
||||
|
||||
+mod interface;
|
||||
+mod print;
|
||||
+
|
||||
/// Entrypoint of the `kernel`.
|
||||
fn kernel_entry() -> ! {
|
||||
- panic!()
|
||||
+ println!("Hello from Rust!");
|
||||
+
|
||||
+ panic!("Stopping here.")
|
||||
}
|
||||
|
||||
diff -uNr 02_runtime_init/src/print.rs 03_hacky_hello_world/src/print.rs
|
||||
--- 02_runtime_init/src/print.rs 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ 03_hacky_hello_world/src/print.rs 2019-09-24 22:30:10.489867506 +0200
|
||||
@@ -0,0 +1,32 @@
|
||||
+// SPDX-License-Identifier: MIT
|
||||
+//
|
||||
+// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
|
||||
+
|
||||
+//! Printing facilities.
|
||||
+
|
||||
+use crate::bsp;
|
||||
+use crate::interface::console::Write;
|
||||
+use core::fmt;
|
||||
+
|
||||
+/// Prints without a newline.
|
||||
+///
|
||||
+/// Carbon copy from https://doc.rust-lang.org/src/std/macros.rs.html
|
||||
+#[macro_export]
|
||||
+macro_rules! print {
|
||||
+ ($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*)));
|
||||
+}
|
||||
+
|
||||
+/// Prints with a newline.
|
||||
+///
|
||||
+/// Carbon copy from https://doc.rust-lang.org/src/std/macros.rs.html
|
||||
+#[macro_export]
|
||||
+macro_rules! println {
|
||||
+ () => ($crate::print!("
|
||||
"));
|
||||
+ ($($arg:tt)*) => ({
|
||||
+ $crate::print::_print(format_args_nl!($($arg)*));
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
+pub fn _print(args: fmt::Arguments) {
|
||||
+ bsp::console().write_fmt(args).unwrap();
|
||||
+}
|
||||
```
|
Loading…
Reference in New Issue