2: Minimal Rust Kernel
- Computer loads BIOS, which loads the bootloader, stored in the first 512 bytes of a bootable disk
- Bootloaders need more space so this initial 512-byte region loads a larger bootloader from elsewhere on the disk
- It then switches the CPU from real mode (16-bit) to protected mode (32-bit) to long mode (64-bit)
- Define a custom target using JSON
core
needs to be rebuilt for custom targets (.cargo/config.toml
)
- Enable the
mem
compiler builtins so functions like memset
are available without a libc
- Printing to the VGA text buffer
- The buffer is located at address
0xb8000
- Each character cell consists of an ASCII byte and a color byte
- Use the bootloader crate instead of writing a custom bootloader
- Use the
bootimage
tool to link the bootloader to the kernel
- Can’t use cargo for this because it apparently doesn’t support post-build scripts
- The kernel is compiled to an ELF binary and the bootloader is linked to it
- It works!
1: Freestanding Rust Binary
#![no_std]
to disable the Rust stdlib
- Define a panic handler (that the stdlib normally handles) with
#[panic_handler]
- The
!
return type indicates that a function doesn’t return
- Disable stack unwinding (which requires OS support) with
panic = "abort"
- Rust binaries (with the stdlib) first invoke
crt0
in the C runtime lib, which invokes _start
in the Rust runtime lib, which then invokes main
- We don’t have a
crt0
to use, so we replace main with our own implementation
- And configure the linker to invoke it
- Switch the rustc/cargo target to
thumbv7em-none-eabihf
- The
none
means “no OS”, any target with none
is suitable here
- This is sufficient to get cargo to use our custom
_start
function