# rust-kernel A tiny hobby x86_64 kernel written in Rust, following the 2nd edition of Philipp Oppermann's [Writing an OS in Rust](https://os.phil-opp.com/). Right now it boots in QEMU, prints a greeting on the VGA text screen and on the serial port (COM1), and then halts. ![boot screenshot](boot.png) ## What's installed (on this box) | Tool | Version | Why | |---|---|---| | rustup | 1.29.2 | toolchain manager (in `~/.cargo/bin`, ahead of Debian's `/usr/bin/cargo`) | | Rust nightly | rustc 1.101.0-nightly (2026-10-29) | custom JSON targets + `build-std` are nightly-only | | `rust-src` component | – | source of `core`, recompiled for our bare-metal target | | `llvm-tools-preview` component | – | `llvm-objcopy` etc., used by `bootimage` | | `bootimage` (cargo subcommand) | 0.10.5 | links kernel + bootloader into a bootable disk image | | QEMU (`qemu-system-x86`) | 10.0.13 | the emulator we boot in | `rust-toolchain.toml` pins the project to nightly with the two components, so `cargo` inside this directory picks them up automatically. Crates: `bootloader` 0.9.35 (BIOS bootloader used by the 2nd edition), `volatile` 0.2, `spin` 0.5, `x86_64` 0.15, `uart_16550` 0.3, `lazy_static` 1.5. Fresh setup on another machine: ```sh curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # rustup rustup toolchain install nightly -c rust-src -c llvm-tools-preview cargo install bootimage sudo apt install qemu-system-x86 ``` ## Build and run ```sh cargo bootimage # build -> target/x86_64-rust_kernel/debug/bootimage-rust_kernel.bin cargo run # build + boot in a QEMU window; serial output also prints in the terminal # (kernel halts forever, close the window or press Ctrl+C to quit) ``` Headless (no window, good for SSH / scripts): ```sh ./scripts/run-headless.sh # builds with --features headless, boots with -display none, # kernel exits QEMU via isa-debug-exit; script exits 0 on success cargo run --features headless -- -display none # same thing via cargo # (QEMU's exit status is 33 = success; cargo just reports it as non-zero) cargo run -- -display none # headless but kernel keeps running; Ctrl+C to stop ./scripts/screenshot.sh [out.png] # boots, saves the VGA screen to boot.png via QEMU monitor `screendump` ``` Expected serial output: ``` Hello from Tyler's Rust kernel! (via serial COM1) Kernel booted successfully. ``` Extra args after `--` in `cargo run -- ...` are appended to the QEMU command line, e.g. `cargo run -- -d int -no-reboot` to debug triple faults, or `cargo run -- -s -S` to wait for `gdb` on port 1234. ## Project layout ``` .cargo/config.toml build-std + custom target + "bootimage runner" as the cargo runner rust-toolchain.toml pin nightly + rust-src + llvm-tools-preview x86_64-rust_kernel.json custom target: no OS, no red zone, soft-float, abort on panic, rust-lld Cargo.toml deps, `headless` feature, QEMU run-args for `cargo run` src/main.rs entry point `_start`, panic handler, QEMU exit helper src/vga_buffer.rs VGA text-mode writer + print!/println! macros src/serial.rs COM1 UART writer + serial_print!/serial_println! macros scripts/run-headless.sh headless boot with timeout + exit-code check scripts/screenshot.sh headless boot + PNG screenshot via QEMU monitor boot.png screenshot of the VGA screen ``` ## Roadmap Already done (roughly chapters 1–3, plus the serial/QEMU-exit bits of chapter 4): - [x] Freestanding binary — [phil-opp](https://os.phil-opp.com/freestanding-rust-binary/) - [x] Minimal kernel booting in QEMU — [phil-opp](https://os.phil-opp.com/minimal-rust-kernel/), [OSDev: Bare Bones](https://wiki.osdev.org/Bare_Bones) - [x] VGA text mode printing — [phil-opp](https://os.phil-opp.com/vga-text-mode/), [OSDev: Printing to Screen](https://wiki.osdev.org/Printing_To_Screen) - [x] Serial output + QEMU exit — [phil-opp: Testing](https://os.phil-opp.com/testing/), [OSDev: Serial Ports](https://wiki.osdev.org/Serial_Ports) Next stages: 1. **Testing** — custom test framework (`cargo test` in QEMU). [phil-opp: Testing](https://os.phil-opp.com/testing/) 2. **CPU exceptions / IDT** — breakpoint & page fault handlers. [phil-opp: CPU Exceptions](https://os.phil-opp.com/cpu-exceptions/), [OSDev: IDT](https://wiki.osdev.org/Interrupt_Descriptor_Table), [OSDev: Exceptions](https://wiki.osdev.org/Exceptions) 3. **GDT / TSS / double faults** — separate stack so stack overflows don't triple-fault. [phil-opp: Double Faults](https://os.phil-opp.com/double-fault-exceptions/), [OSDev: GDT](https://wiki.osdev.org/Global_Descriptor_Table), [OSDev: TSS](https://wiki.osdev.org/Task_State_Segment) 4. **Hardware interrupts** — 8259 PIC, timer, PS/2 keyboard. [phil-opp: Hardware Interrupts](https://os.phil-opp.com/hardware-interrupts/), [OSDev: 8259 PIC](https://wiki.osdev.org/8259_PIC), [OSDev: PIT](https://wiki.osdev.org/Programmable_Interval_Timer), [OSDev: PS/2 Keyboard](https://wiki.osdev.org/PS/2_Keyboard) (later: [APIC](https://wiki.osdev.org/APIC)) 5. **Paging** — 4-level page tables, mapping frames. [phil-opp: Introduction to Paging](https://os.phil-opp.com/paging-introduction/), [phil-opp: Paging Implementation](https://os.phil-opp.com/paging-implementation/), [OSDev: Paging](https://wiki.osdev.org/Paging) 6. **Heap allocation** — `alloc` crate, `Box`/`Vec`, allocator designs. [phil-opp: Heap Allocation](https://os.phil-opp.com/heap-allocation/), [phil-opp: Allocator Designs](https://os.phil-opp.com/allocator-designs/), [OSDev: Memory Allocation](https://wiki.osdev.org/Memory_Allocation) 7. **Multitasking** — cooperative async/await executor first, then preemptive threads. [phil-opp: Async/Await](https://os.phil-opp.com/async-await/), [OSDev: Multitasking Systems](https://wiki.osdev.org/Multitasking_Systems), [OSDev: Brendan's Multi-tasking Tutorial](https://wiki.osdev.org/Brendan%27s_Multi-tasking_Tutorial) 8. **User mode & syscalls** — ring 3, `syscall`/`sysret`, loading ELF programs. (Beyond the phil-opp series.) [OSDev: Getting to Ring 3](https://wiki.osdev.org/Getting_to_Ring_3), [OSDev: System Calls](https://wiki.osdev.org/System_Calls), [OSDev: SYSENTER/SYSCALL](https://wiki.osdev.org/SYSENTER), [OSDev: ELF](https://wiki.osdev.org/ELF) 9. **Filesystem & shell** — VFS, a RAM disk / FAT, a tiny shell reading the keyboard. [OSDev: File Systems](https://wiki.osdev.org/File_Systems), [OSDev: VFS](https://wiki.osdev.org/VFS), [OSDev: FAT](https://wiki.osdev.org/FAT), [OSDev: Initrd](https://wiki.osdev.org/Initrd) Other good references: [OSDev wiki main page](https://wiki.osdev.org/Expanded_Main_Page), [Intel SDM](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdms.html), the [blog_os repo](https://github.com/phil-opp/blog_os) (one branch per post, e.g. `post-04`), and for a UEFI/framebuffer setup later, the newer [`bootloader` 0.11](https://github.com/rust-osdev/bootloader) crate. ## Notes / gotchas - The target JSON changes occasionally with new nightlies (e.g. `target-pointer-width` became an integer, `rustc-abi` was added). If a nightly update breaks the build, compare with the latest `x86_64-blog_os.json` in the blog_os repo, or pin a date in `rust-toolchain.toml` (`channel = "nightly-2026-10-29"`). - The "packages contain code that will be rejected by a future version of Rust: core" warning comes from building `core` with build-std and is harmless. - `bootimage` prints "`CARGO_MANIFEST_DIR` env variable not set" when run outside `cargo run`; also harmless.