rust-raspberrypi-OS-tutorials/03_hacky_hello_world/README.md

245 lines
7.3 KiB
Markdown
Raw Normal View History

2019-09-25 09:56:41 +00:00
# Tutorial 03 - Hacky Hello World
## tl;dr
2020-03-28 12:27:14 +00:00
Introducing global `print!()` macros to enable "printf debugging" at the earliest; To keep tutorial
length reasonable, printing functions for now "abuse" a QEMU property that lets us use the RPi's
`UART` without setting it up properly; Using the real hardware `UART` is enabled step-by-step in
following tutorials.
2019-09-25 09:56:41 +00:00
2020-03-28 12:27:14 +00:00
## Notable additions
2019-09-25 09:56:41 +00:00
2020-03-28 12:27:14 +00:00
- `src/console.rs` introduces interface `Traits` for console commands.
- `src/bsp/rpi.rs` implements the interface for QEMU's emulated UART.
- The panic handler makes use of the new `print!()` to display user error messages.
2019-10-21 19:46:55 +00:00
2020-03-28 12:27:14 +00:00
## Test it
QEMU is no longer running in assembly mode. It will from now on show the output of the `console`.
2019-10-21 19:46:55 +00:00
```console
2020-03-28 12:27:14 +00:00
$ make qemu
2019-10-21 19:46:55 +00:00
[...]
Hello from Rust!
2020-03-28 12:27:14 +00:00
2019-10-21 19:46:55 +00:00
Kernel panic: Stopping here.
```
2019-09-25 09:56:41 +00:00
## Diff to previous
2020-03-28 14:42:42 +00:00
```diff
diff -uNr 02_runtime_init/Makefile 03_hacky_hello_world/Makefile
--- 02_runtime_init/Makefile
+++ 03_hacky_hello_world/Makefile
2020-04-12 20:22:29 +00:00
@@ -11,7 +11,7 @@
2020-04-16 20:46:11 +00:00
KERNEL_BIN = kernel8.img
2020-04-12 20:22:29 +00:00
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE = raspi3
- QEMU_RELEASE_ARGS = -d in_asm -display none
+ QEMU_RELEASE_ARGS = -serial stdio -display none
LINKER_FILE = src/bsp/raspberrypi/link.ld
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
2020-03-28 14:42:42 +00:00
else ifeq ($(BSP),rpi4)
2020-04-12 20:22:29 +00:00
@@ -19,7 +19,7 @@
2020-04-16 20:46:11 +00:00
KERNEL_BIN = kernel8.img
2020-04-12 20:22:29 +00:00
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE =
- QEMU_RELEASE_ARGS = -d in_asm -display none
+ QEMU_RELEASE_ARGS = -serial stdio -display none
LINKER_FILE = src/bsp/raspberrypi/link.ld
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72
2020-03-28 14:42:42 +00:00
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-2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! 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,4 @@
//! Top-level BSP file for the Raspberry Pi 3 and 4.
-// Coming soon.
+pub mod console;
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-2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! 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
2020-06-29 20:27:31 +00:00
@@ -93,7 +93,9 @@
2020-03-28 14:42:42 +00:00
//! - `crate::bsp::memory::*`
2020-06-29 20:27:31 +00:00
#![feature(asm)]
2020-03-28 14:42:42 +00:00
+#![feature(format_args_nl)]
#![feature(global_asm)]
+#![feature(panic_info_message)]
#![no_main]
#![no_std]
@@ -101,9 +103,11 @@
// `runtime_init()`, which jumps to `kernel_init()`.
mod bsp;
+mod console;
mod cpu;
mod memory;
mod panic_wait;
+mod print;
mod runtime_init;
/// Early init code.
@@ -112,5 +116,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,42 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
+
+//! Printing facilities.
+
+use crate::{bsp, console};
+use core::fmt;
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+#[doc(hidden)]
+pub fn _print(args: fmt::Arguments) {
+ use console::interface::Write;
+
+ bsp::console::console().write_fmt(args).unwrap();
+}
+
+//--------------------------------------------------------------------------------------------------
+// Public Code
+//--------------------------------------------------------------------------------------------------
+
+/// 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!("\n"));
+ ($($arg:tt)*) => ({
+ $crate::print::_print(format_args_nl!($($arg)*));
+ })
+}
```