Add first bunch of README stubs

pull/35/head
Andre Richter 5 years ago
parent f9020bbb03
commit 651097d55e
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -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…
Cancel
Save