Hello, World!

Run the hello world example:

cd workspaces/root-task/hello-world
make simulate

Press ctrl-a x to exit QEMU.

Here is its source:

The Rust standard library is divided into three layers:

  • core: dependency-free foundation
  • alloc: implements heap-backed data structures, but requires a runtime that provides a heap allocator
  • std includes core and alloc, and adds APIs that depend on OS services such as networking and filesystems

The high-level std doesn't support the low-level seL4 root task target. #![no_std] declares that this crate does not depend on std, and prevents rustc from automatically importing it.

Our language runtime will handle the program's entrypoint differently than a typical Rust program. #![no_main] informs rustc of this fact.

The sel4 crate binds the seL4 API. It is generated from source (.xml, .bf, and .h) in libsel4. We will cover the contents of this crate in future chapters.

The sel4_root_task crate implements a Rust language runtime for the root task environment.

The #[root_task] attribute macro declares a function to be the root task's entrypoint. The entrypoint function must have a signature of the form:

fn(&sel4::BootInfoPtr) -> T
where
    T: sel4_root_task::Termination

(Rustdoc for BootInfoPtr and Termination)

The root task has no way to exit, so, to terminate cleanly, it must suspend its own thread. sel4::init_thread::suspend_self() does exactly this.

Step 2.A (exercise)       

Exercise: Cause a panic.

Step 2.B (exercise)       

Exercise: Catch the panic using sel4_root_task::panicking::catch_unwind().

Step 2.C (exercise)       

You can set a custom panic hook with sel4_root_task::panicking::PanicHook. The default hook just prints the panic's ExternalPanicInfo.

Exercise: Set a custom panic hook.

Step 2.D (exercise)       

Exercise: Cause a stack overflow.

Step 2.E (exercise)       

The #[root_task] attribute macro accepts a named stack_size parameter, which can be any expression of type usize and whose value is interpreted as the root task's initial thread's stack size, in bytes. For example:

#[root_task(stack_size = 13 * 37)]

The default stack size is sel4_root_task::DEFAULT_STACK_SIZE.

Exercise: Adjust the root task's initial thread's stack size to prevent the stack overflow you just caused.

Step 2.F (exercise)       

By default, the sel4_root_task runtime does not include a heap. Any attempt to use the alloc crate will result in a link-time failure.

The #[root_task] attribute macro accepts a heap_size parameter, which can be any expression of type usize and whose value is interpreted as the root task's heap size, in bytes. Note that heap_size must come after stack_size in the case where both are present. For example:

#[root_task(heap_size = 0xf00d)]

or

#[root_task(stack_size = 13 * 37, heap_size = 0xf00d)]

Exercise: Add a heap and use it.

Step 2.G       

The sel4_logging crate builds on top of the log crate to add utilities for initializing simple loggers in minimal environments, such as a seL4 root task. This step demonstrates one way to initialize a logger using this crate: