RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / Cargo.toml
9117 bytes ยท raw
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
[package]
name = "rustbelt"
version = "0.13.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",
    # 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)
    # 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