Writing an OS in Rust

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! 500

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