rust-kernel
Rustbelt: a hobby x86_64 kernel written in Rust
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | [package]
name = "rustbelt"
version = "0.15.0"
edition = "2024"
[dependencies]
# Bootloader 0.9.x: the version used by the 2nd edition of "Writing an OS in Rust".
# `cargo bootimage` links it with our kernel into a bootable BIOS disk image.
# `map_physical_memory`: the bootloader maps *all* physical RAM somewhere in
# virtual memory and tells us where (BootInfo.physical_memory_offset), so we
# can read/write page tables, which live at physical addresses.
bootloader = { version = "0.9", features = ["map_physical_memory"] }
volatile = "0.2.6" # stops the compiler optimising away VGA buffer writes
spin = "0.5.2" # spinlock Mutex (no OS = no std::sync::Mutex)
x86_64 = "0.15" # safe wrappers for x86 instructions/ports (hlt, outb, ...)
uart_16550 = "0.3" # driver for the serial port (COM1)
pic8259 = "0.11" # driver for the two chained 8259 interrupt controllers
pc-keyboard = "0.7" # turns PS/2 scancodes into key events / characters
linked_list_allocator = "0.9" # ready-made heap allocator (fallback for ours)
# Async/await support without std (all with default features off):
crossbeam-queue = { version = "0.3.11", default-features = false, features = ["alloc"] } # lock-free ArrayQueue
conquer-once = { version = "0.4", default-features = false } # OnceCell: init a static at runtime, once
futures-util = { version = "0.3.4", default-features = false, features = ["alloc"] } # Stream, AtomicWaker
# FAT12/16/32 file system library. The crates.io release (0.3.6) needs the
# abandoned `core_io` crate for no_std, so we use the git version, pinned to
# an exact commit so builds are reproducible. Only `alloc` + long file names.
fatfs = { git = "https://github.com/rafalh/rust-fatfs", rev = "38b3a7950bf0e765e34286d1dfe76c519ee347e2", default-features = false, features = ["alloc", "lfn"] }
# Decompressors for btrfs's compressed extents (stage 10). Only decompression
# is used; the btrfs driver itself is hand-written. Both work without std.
miniz_oxide = { version = "0.8", default-features = false, features = ["with-alloc"] } # zlib (DEFLATE)
ruzstd = { version = "0.8", default-features = false } # zstd
# TCP/IP: Ethernet, ARP, IPv4, ICMP, UDP, TCP, DHCP and DNS, written for
# kernels and microcontrollers (no_std, works without an OS).
smoltcp = { version = "0.14", default-features = false, features = [
"alloc", "medium-ethernet", "proto-ipv4",
"socket-tcp", "socket-udp", "socket-icmp", "socket-dhcpv4", "socket-dns",
] }
[dependencies.lazy_static]
version = "1.0"
features = ["spin_no_std"]
[features]
# Build with `--features headless` to make the shell run the self-test
# script (disk/scripts/selftest.sh) instead of reading the keyboard, and shut
# QEMU down when it exits (used by scripts/run-headless.sh).
headless = []
# Build with `--features demos` to see the earlier stages' demos at boot:
# breakpoint, paging/heap printouts, threads A/B/C, async tasks and the
# hello/evil/spin/demo programs (before the shell starts).
demos = []
# Build with `--features stack-overflow` to deliberately overflow the kernel
# stack after boot, to check the double-fault handler (GDT/TSS/IST) catches it.
stack-overflow = []
# Build with `--features page-fault` to deliberately write to an unmapped
# address after boot and watch the page-fault handler report it.
page-fault = []
# The library (src/lib.rs) holds all kernel code so integration tests in
# tests/ can use it; src/main.rs is the small binary that boots it.
[lib]
doctest = false # doc tests would need std; our tests run in QEMU instead
[[bin]]
name = "rustbelt"
test = false # all tests live in the library and tests/
bench = false
# These two tests replace the test framework with their own `_start`.
[[test]]
name = "should_panic"
harness = false
[[test]]
name = "stack_overflow"
harness = false
# Note: no `panic = "abort"` profile settings: the target JSON already sets
# "panic-strategy": "abort", and the profile setting breaks `cargo test` with
# build-std ("duplicate lang item in crate core").
# Extra QEMU arguments used by `cargo run` (via `bootimage runner`).
[package.metadata.bootimage]
run-args = [
# Four CPU cores (smp.rs starts the other three).
"-smp", "4",
# The most capable CPU QEMU can emulate: it has XSAVE and AVX (the
# default "qemu64" model has neither, only FXSAVE + SSE2). fpu.rs
# handles both.
"-cpu", "max",
# Second disk: the FAT32 image build.rs makes (target/disk.img), as a
# virtio-blk PCI device. snapshot=on: writes go to a temporary overlay,
# so the image is the same at every boot (and tests can't corrupt it).
"-drive", "file=target/disk.img,format=raw,if=virtio,snapshot=on",
# Third disk: the ext2 image (target/ext2.img), also snapshot=on.
"-drive", "file=target/ext2.img,format=raw,if=virtio,snapshot=on",
# Fourth disk: the exFAT image (target/exfat.img), drive D:.
"-drive", "file=target/exfat.img,format=raw,if=virtio,snapshot=on",
# Fifth disk: the btrfs image (target/btrfs.img), drive E: (read-only).
"-drive", "file=target/btrfs.img,format=raw,if=virtio,snapshot=on",
# Network card: virtio-net on QEMU's user-mode network ("slirp"): a
# built-in NAT router with DHCP (we get 10.0.2.15), the host as
# 10.0.2.2 and a DNS forwarder at 10.0.2.3. No root or setup needed.
# guestfwd: connections to 10.0.2.100:80 run scripts/http-reply.sh
# (a test web server); 10.0.2.100:7 runs `cat` (an echo server).
# hostfwd: the host's port 5580 reaches the guest's port 80, so
# `httpd` in Rustbelt answers `curl http://127.0.0.1:5580/`.
"-netdev", "user,id=net0,guestfwd=tcp:10.0.2.100:80-cmd:sh scripts/http-reply.sh,guestfwd=tcp:10.0.2.100:7-cmd:cat,hostfwd=tcp:127.0.0.1:5580-:80",
"-device", "virtio-net-pci,netdev=net0",
# Stage 13's virtual devices:
# virtio-vga: virtio-gpu that also does the old VGA modes (so the
# BIOS and the early VGA text console still work). -vga none drops
# the default "std" VGA card it replaces.
# virtio-rng-pci: random numbers from the host.
# virtio-serial-pci + virtconsole: a second terminal (hvc0) on a unix
# socket: `socat - UNIX-CONNECT:target/hvc0.sock` on the host, and
# `getty /dev/hvc0 &` in Rustbelt to get a shell there.
"-vga", "none", "-device", "virtio-vga",
"-device", "virtio-rng-pci",
"-device", "virtio-serial-pci", "-device", "virtconsole,chardev=hvc",
"-chardev", "socket,id=hvc,path=target/hvc0.sock,server=on,wait=off",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", # lets the kernel exit QEMU
"-serial", "stdio", # serial port -> your terminal
]
# Used by `cargo test`: headless, results on serial, exit code 33 = pass.
test-args = [
"-smp", "4", # four CPU cores (tests that call init_smp use them all)
"-cpu", "max", # XSAVE + AVX (fpu.rs; the default qemu64 has only FXSAVE)
# Second disk: the FAT32 image build.rs makes (target/disk.img), as a
# virtio-blk PCI device. snapshot=on: writes go to a temporary overlay,
# so the image is the same at every boot (and tests can't corrupt it).
"-drive", "file=target/disk.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/ext2.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/exfat.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/btrfs.img,format=raw,if=virtio,snapshot=on",
# More images just for the tests, after the ones `cargo run` has so the
# drive letters B: to E: are the same in both: ext2 with 4 KiB blocks
# (/mnt/disk4), ext2 revision 0 (/mnt/disk5), exFAT with 512-byte
# clusters (/mnt/disk6), btrfs with lzo (/mnt/disk7), zstd (/mnt/disk8),
# converted from ext2 (/mnt/disk9), and one with sha256 checksums that
# must be refused (so it gets no /mnt/diskN).
"-drive", "file=target/ext2-4k.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/ext2-rev0.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/exfat-512.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/btrfs-lzo.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/btrfs-zstd.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/btrfs-convert.img,format=raw,if=virtio,snapshot=on",
"-drive", "file=target/btrfs-sha256.img,format=raw,if=virtio,snapshot=on",
# Network (see run-args), plus slirp's TFTP server serving disk/ (a UDP
# test). No hostfwd: tests must not depend on a free host port.
"-netdev", "user,id=net0,tftp=disk,guestfwd=tcp:10.0.2.100:80-cmd:sh scripts/http-reply.sh,guestfwd=tcp:10.0.2.100:7-cmd:cat",
"-device", "virtio-net-pci,netdev=net0",
# The stage-13 devices (see run-args). The console's input comes from
# tests/hvc0-input.txt and its output goes to target/hvc0-test.out.
"-vga", "none", "-device", "virtio-vga",
"-device", "virtio-rng-pci",
"-device", "virtio-serial-pci", "-device", "virtconsole,chardev=hvc",
"-chardev", "file,id=hvc,path=target/hvc0-test.out,input-path=tests/hvc0-input.txt",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
"-serial", "stdio",
"-display", "none",
]
test-success-exit-code = 33 # (0x10 << 1) | 1
test-timeout = 120 # seconds
|