Chronosapien
A beginner-friendly hobby OS in Rust.
Overview
Chronosapien is a hobby operating system written in Rust. It boots a no_std x86_64 kernel in QEMU, renders a framebuffer graphics console, logs to serial, and runs a tiny era-themed shell on top of an in-memory filesystem.
It is intentionally small. The point is not to compete with Linux or even Redox — it is to keep every layer readable end to end, so a beginner can open the repo and follow how a machine becomes an operating system.
Why I'm building it
Most of my work lives in JavaScript runtimes that hide the machine. Chronosapien is a bet that I understand systems better if I am forced to write them — interrupts, page faults, framebuffers, keyboards, and all.
Rust forces honesty about ownership and lifetimes even when talking to hardware. no_stdforces honesty about what the standard library was actually doing for me. Both are exactly the pressure I wanted.
Current state
The kernel boots reliably in QEMU. Serial output works from very early in the boot process so debugging is possible without a screen. The framebuffer console prints text and accepts input. CPU exceptions, the timer, and PS/2 keyboard are wired through a real IDT.
Memory management is bump-allocated for now. The filesystem lives in RAM. The shell ships with a small set of useful commands and a few built-in apps.
Architecture
- Bootloader crate sets up long mode, hands the kernel a framebuffer and memory map.
- Kernel entrypoint initializes serial logging first, then the framebuffer console, GDT, IDT, PIC remap, and PIT timer.
- Memory subsystem manages a bump heap and tracks the memory map handed in by the bootloader.
- Filesystem is a simple in-memory tree with files and metadata.
- Shell polls the keyboard and dispatches into a small command table that includes apps like notes, calc, and sysinfo.
Boot flow in plain English
- QEMU emulates an x86_64 machine and loads the bootloader.
- The bootloader prepares CPU state and switches to long mode.
- It hands the kernel a framebuffer pointer and a memory map.
- The Rust kernel entrypoint runs.
- Serial logging initializes — debug output works from now on.
- The framebuffer console initializes — the screen shows text.
- GDT and IDT load — the CPU knows how to handle exceptions.
- The timer (PIT) starts ticking.
- The PS/2 keyboard is enabled.
- The shell loop begins, waiting for the first keystroke.
Features already working
- Serial logging with a working
println!-style macro - Framebuffer text console with scrolling
- GDT, IDT, breakpoint / page fault / double fault handlers
- PIC remap and PIT timer interrupts
- PS/2 keyboard input through an IRQ handler
- Bump-allocated heap
- In-memory filesystem with files and listings
- Shell commands:
ls,cat,write,rm,mem,uptime,clock,clear,reboot, era switching - Built-in apps: notes, calc, sysinfo
Hard parts
Triple faults that boot-loop the VM with no output. The fix is always the same — ship serial logging before anything else, then add prints aggressively while you isolate the line that broke the world.
Calling conventions and frame layouts for interrupt handlers. Rust's type system helps but the hardware does not negotiate.
Memory management without a real allocator. A bump heap is fine while learning, but it forces you to think about lifetimes the way Rust wanted you to all along.
What I learned
Logging is more important than features. If you cannot print, you cannot debug, and nothing else matters.
Frameworks hide a staggering amount of work. Drawing a glyph yourself changes how you think about every UI you have ever shipped.
Small, readable code beats clever, dense code in this domain. The whole project is a teaching artifact for me first.
Roadmap
- Replace the bump heap with a real allocator
- Persist the in-memory filesystem to a virtual disk
- Userspace processes and a basic syscall layer
- Better framebuffer rendering: fonts, basic graphics primitives
- Networking stack experiments
- A long-form OS boot-flow visualizer on this site