Ferro is a hobby operating system for 64-bit ARM (AArch64), written from scratch in Rust.
Most hobby OSes stop at a text shell that prints "hello world". Ferro boots all the way to a graphical desktop with draggable windows, ships its own web browser engine, and runs DOOM in a window. It's a learning project I work on for fun, but the desktop, networking, persistence, and browser stacks are real enough to actually demo.
- A Rust AArch64 kernel built from the ground up: memory management, exceptions and interrupts, a timer, a scheduler, and a RAM-backed filesystem.
- A desktop environment with resizable windows, a launcher, a dock, notifications, and a lock screen. Bundled apps: terminal, file manager, text editor, calculator, settings, system monitor, clock, Snake, image gallery, the Forge browser, and DOOM.
- Forge, a browser engine running inside the OS. It has its own HTML parser, CSS cascade,
layout (block/inline/flex/grid/table), painting, a JS↔DOM bridge,
fetch/XHR, tabs, history, bookmarks, find-in-page, and small DevTools panes. (How far it actually gets is covered below.) - DOOM, running through PureDOOM off a VirtIO block image, windowed by default with optional sound.
- VirtIO drivers for GPU, input (keyboard/mouse/tablet), networking, block storage, 9P host file sharing, and sound.
- Optional persistence: when QEMU shares a host folder over 9P, Ferro saves browser data, desktop settings, and panic logs to it. Without it, everything lives in RAM and resets on reboot.
Captured from QEMU's VirtIO-GPU framebuffer.
| Desktop and launcher | Files app |
|---|---|
![]() |
![]() |
| Forge browser | DOOM app |
|---|---|
![]() |
![]() |
Ferro is macOS + QEMU first right now. You'll need:
- macOS with the Hypervisor framework (
hvf) - QEMU with
qemu-system-aarch64 - Rust nightly with
rust-src,rustfmt,clippy, and theaarch64-unknown-none-softfloattarget. The checked-inrust-toolchain.tomlpulls these in. - A host C compiler for the PureDOOM build (Xcode Command Line Tools works)
make build # build the release kernel
make run # boot the desktop in a window
make run-doom # same, with DOOM ready to launch from the dockmake run opens the desktop in a Cocoa window and mirrors serial output to your terminal. It also
sets up the default host-share folder (mounted inside Ferro at /host) and makes sure
artifacts/doom.img exists so DOOM can launch.
Other make targets
make check # cargo fmt --check + release build
make test-unit # host-side source/fixture checks (not Rust unit tests yet)
make smoke # boot a desktop smoke kernel headless and wait for "Desktop ready"
make smoke-doom # boot a DOOM smoke kernel headless and wait for the first frame
make test-render # boot a render-smoke kernel and validate the captured PPM
make run-nographic # default device set, no Cocoa window
make run-serial # serial-focused debug boot
make size # print the release kernel size
make doom-image IWAD=/abs/path/to/doom2.wad # rebuild artifacts/doom.img from a legal IWAD
make cleanThe default host share is $(pwd)/host-share; override with HOST_SHARE=/abs/path make run. The
DOOM image defaults to artifacts/doom.img and can be overridden with DOOM_IMG=/abs/path.
src/main.rs— boot sequence and subsystem bring-upsrc/mm,src/exceptions.rs,src/gic.rs,src/timer.rs,src/scheduler.rs— kernel plumbingsrc/metrics.rs— boot/frame/memory/CPU counters shown in System Monitor andperfsrc/drivers/virtio— VirtIO probing plus the GPU, input, network, block, 9P, and sound driverssrc/net— TCP/IP, HTTP, TLS, cookiessrc/fs— a VFS over RAMFS plus the optional/host9P sharesrc/gui— compositor, widgets, themes, windows, and the bundled appssrc/gui/apps/browser— the Forge engine: layout/render pipeline, JS/DOM, settings, history, DevToolssrc/doom— the PureDOOM wrapper, IWAD volume loading, input, and audiotests/fixtures/render— browser render fixtures for regression checks
Ferro always boots with an in-memory RAM filesystem. On the default QEMU path it also mounts a 9P
host share at /host. When that share is present, Ferro stores browser settings/history/bookmarks,
desktop timezone settings, and panic logs under /host/.ferro. Without 9P it falls back to
/home/user/.config/ferro in RAMFS, so state doesn't survive a reboot. Only paths under /host
are host-persistent; /home, /tmp, and /etc are RAM-backed.
Forge is real and surprisingly capable for a hobby-OS browser, but it is nowhere near modern
browser compatibility. Treat it as a browser-engine lab that happens to run inside Ferro, not a
safe everyday browser. A site like google.com may load but won't fully render or behave correctly.
- Works today: HTML parsing, CSS cascade, block/inline/flex/grid/table layout, painting, DOM
mutation, event dispatch from input, timers,
fetch,XMLHttpRequest, forms, text selection, find-in-page, basic canvas, a minimal SVG subset, image decoding, bookmarks, history, download metadata, settings, and simple DevTools panes. - HTTPS uses rustls with the
webpki-rootstrust store, and fails closed on bad chains, names, dates, or unsupported signatures. - Not there yet:
<video>/<audio>are layout-only stubs with no decoders; canvas is partial (drawImage()and image-data round-trips are stubbed); SVG is an inline subset, not full SVG/MathML; CSS media-query and viewport handling are simplified; networking is HTTP/1.1 withConnection: closeand no compression yet; complex JS apps still hit missing APIs.
- The default
artifacts/doom.imgis built from the bundled sharewarethird_party/puredoom/doom1.wad. - DOOM launches windowed at the largest integer multiple of
320x200that fits the desktop. - Click inside the window to capture input;
F11for fullscreen,Ctrl+Alt+Gto release the mouse. - Sound turns on when QEMU exposes a compatible stereo S16 PCM stream, otherwise it's hidden.
- Swap in another legal IWAD with
make doom-image IWAD=/abs/path/to/doom2.wad.
- macOS-first; tuned for QEMU's
hvfaccelerator and the Cocoa display backend. make checkpasses but emits some dead-code warnings around filesystem/memory helpers.cargo testisn't wired up yet — the custom target needs a dedicated test strategy first.- The VirtIO block path is mostly a DOOM-volume path, not a general persistent filesystem.
- The compositor still flushes whole frames; dirty-rectangle flushing is future work.
MIT — see LICENSE.



