A minimal, modular bare-metal bootloader for RISC-V written in Rust. Designed to run directly on RISC-V hardware (and QEMU) without any firmware, loading kernels from memory or disk.
Implemented
- ✅ Bare-metal assembly entry point with stack setup and BSS clearing
- ✅ Machine-mode trap handling
- ✅ UART driver for debug output (16550-compatible)
- ✅ Frame allocator for memory management
- ✅ ELF64 kernel loader with segment loading
- ✅ VirtIO block device driver
- ✅ Multi-hart support (secondary harts parked)
Planned
- 🔲 MBR/GPT partition table parsing
- 🔲 EXT2/3/4 filesystem support
- 🔲 Device Tree (DTB) parsing and forwarding
- 🔲 Kernel command line support
- Rust nightly toolchain
- QEMU for RISC-V emulation (for testing)
# Install the RISC-V target
rustup target add riscv64gc-unknown-none-elf
# Install optional tools for binary inspection
rustup component add llvm-tools-preview
cargo install cargo-binutils# Debug build
cargo build
# Release build (optimized)
cargo build --release
# Or use Make
make release# Using Make
make run
# Or manually
qemu-system-riscv64 \
-machine virt \
-bios none \
-kernel target/riscv64gc-unknown-none-elf/release/rustyboot-riscv \
-m 128M \
-nographic \
-serial mon:stdioExpected output:
========================================
RustyBoot-RISCV Bootloader
========================================
[BOOT] Starting bootloader...
[BOOT] UART initialized
[MEM] Initializing memory allocator
[MEM] Frame allocator ready
[DISK] Probing for VirtIO block device...
[DISK] No VirtIO block device found
[BOOT] Loading kernel...
[BOOT] Checking for kernel at 0x80200000
[BOOT] No ELF header found, treating as raw binary
[BOOT] Jumping to kernel at 0x80200000
========================================
qemu-system-riscv64 \
-machine virt \
-bios none \
-kernel target/riscv64gc-unknown-none-elf/release/rustyboot-riscv \
-m 128M \
-nographic \
-serial mon:stdio \
-drive file=disk.img,if=none,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0| Address Range | Description |
|---|---|
0x80000000 - 0x80100000 |
Bootloader code and stack |
0x80100000 - 0x80200000 |
Bootloader heap |
0x80200000 - 0x81000000 |
Kernel load area |
0x81000000 - 0x82000000 |
Frame allocator pool |
RustyBoot-RISCV/
├── src/
│ ├── main.rs # Rust entry point
│ ├── entry.S # Assembly startup code
│ ├── panic.rs # Panic handler
│ ├── config.rs # Configuration constants
│ ├── bootloader.rs # Kernel loading logic
│ ├── uart/ # UART driver
│ ├── memory/ # Frame allocator
│ ├── block/ # VirtIO block driver
│ ├── fs/ # Filesystem support (WIP)
│ └── elf/ # ELF loader
├── linker.ld # Linker script
├── Cargo.toml
├── Makefile
└── .cargo/config.toml # Build configuration
- Entry Point (
entry.S): Sets up stack, clears BSS, installs trap handler - UART Init: Enables debug output through serial console
- Memory Init: Initializes frame allocator for dynamic memory
- VirtIO Probe: Checks for block devices
- Kernel Load: Loads kernel from
0x80200000(ELF or raw binary) - Jump to Kernel: Transfers control with hart ID and DTB pointer
Contributions are welcome! Areas of interest:
- Device driver improvements (SPI, I2C, etc.)
- Filesystem support (FAT32, EXT4)
- Real hardware testing
- SBI implementation
- Maintain
#![no_std]compatibility - Follow the modular structure
- Test with QEMU before submitting
GPLv3 - See LICENSE for details.