A microkernel written in Rust for AArch64, featuring L4-style synchronous IPC, user-space device drivers, and a VFS layer with FAT32 support.
The kernel boots on QEMU virt and runs multiple user-space servers:
- Console server - UART driver, handles stdin/stdout, forwards to framebuffer
- VFS server - Virtual filesystem with ramfs and FAT32
- Block device server - VirtIO-blk driver
- Network device server - VirtIO-net driver
- Pipe server - Blocking pipes with deferred IPC replies
- Framebuffer server - VirtIO-GPU or ramfb with text console (800x600)
- Keyboard server - VirtIO-input driver for GUI keyboard input
- Init process - System startup and shell launching
Phase 3 Complete: BusyBox shell runs interactively! The kernel now includes
alignment fault emulation for SIMD instructions, allowing unmodified musl-based
binaries to run. Type commands at the / # prompt.
DOOM runs on Kenix! (2026-02-10) The original DOOM (linuxdoom-1.10) has been ported to run on Kenix. Renders at 320x200 scaled 2x on the framebuffer with keyboard input via non-blocking console IPC.
Recent Changes (2026-02-10):
- DOOM port: Classic DOOM runs with framebuffer graphics and keyboard input
- Non-blocking console read: Added MSG_READ_NONBLOCK for game loops that poll input
- Arrow key support: Terminal escape sequence parsing (ESC [ A/B/C/D)
- SYS_LSEEK: File seeking with VFS integration
- Cross-task page faults: Kernel can now fault in pages for blocked tasks during IPC reply, fixing crashes when copying data to unmapped mmap regions
- 64-bit defaults fix: Fixed memory corruption in DOOM's config system caused by writing 8-byte intptr_t values to 4-byte int locations on ARM64
Previous Fixes (2026-02-08):
- Framebuffer output for shell via console server IPC
- Fixed sys_writev bypassing console server
- Fixed fbdev/shell race condition with init synchronization
- Blocking pipes via deferred IPC replies
- Address space memory corruption fix for fork+execve
- Relative path resolution in execve
Tested features: IPC, shared memory, blocking pipes, file operations, process spawn/execve, fork/wait, mmap/munmap (anonymous and file-backed), clock_gettime, signal delivery, writev/readv, FAT32 disk I/O, interactive shell (ppoll blocking on stdin).
- QEMU virt (dev)
- Raspberry Pi 4/5 (planned)
- ARM Chromebook (planned)
# Rust nightly
rustup override set nightly
rustup component add rust-src
# QEMU
brew install qemu # macOS
apt install qemu-system-aarch64 # Linux
# mtools (for FAT32 disk images)
brew install mtools # macOS
apt install mtools # Linux# Build the kernel and user-space programs
make
# Run on QEMU (serial console only)
make run-kernel
# Run with graphical display (shows framebuffer)
make run-kernel-fb
# BusyBox shell will display "/ #" prompt
# Type commands like: echo hello, ls, cat /etc/passwd
# Press Ctrl+A X to exit QEMU# Copy DOOM and WAD file to disk image (already done if using provided disk.img)
mcopy -o -i disk.img user/doom/doom.elf ::/doom
mcopy -o -i disk.img doom1.wad ::/doom1.wad
# Run with framebuffer
make run-kernel-fb
# In shell:
/ # /disk/doom -iwad /disk/doom1.wadControls: WASD/Arrows=move, F=fire, E/Space=use, Q=strafe, 1-7=weapons, ESC=menu
[console] Server started
[vfs] Server started
[blkdev] VirtIO ready
[netdev] MAC: 52:54:00:12:34:56
[pipeserv] ok, ready!
=== Kenix Init ===
[vfs] Block device connected
[vfs] FAT32 filesystem mounted at /disk/
--- Starting BusyBox Shell ---
shell pid=7
/ # export PATH=/disk/bin
/ # ls
disk hello.txt test.txt
/ # ls /disk
BIN DATA HELLO.TXT TEST.TXT
/ # cat /hello.txt
Hello!
/ # exit
=== Init complete ===
kenix/
βββ boot/ # UEFI bootloader
βββ kernel/ # Microkernel core
β βββ src/
β βββ main.rs # Kernel entry point
β βββ mm/ # Memory management (paging, frames)
β βββ sched/ # Scheduler and task management
β βββ exception/ # Exception/interrupt handling
β βββ ipc.rs # IPC syscalls
β βββ shm.rs # Shared memory
β βββ syscall.rs # Syscall dispatcher
β βββ gic.rs # ARM GIC driver
β βββ timer.rs # ARM timer driver
β βββ elf.rs # ELF loader
β βββ irq.rs # IRQ-to-task routing
β βββ signal.rs # Signal delivery and handling
β βββ mmap.rs # Anonymous mmap with demand paging
βββ user/ # User-space programs (all Rust)
β βββ libkenix/ # Shared runtime library
β β βββ Cargo.toml
β β βββ src/lib.rs # Syscalls, IPC, SHM wrappers
β βββ console/ # Console server
β β βββ Cargo.toml
β β βββ src/main.rs # UART driver, IPC message loop
β βββ init/ # Init process
β β βββ Cargo.toml
β β βββ src/main.rs # System tests, VFS client
β βββ vfs/ # VFS server
β β βββ Cargo.toml
β β βββ src/
β β βββ main.rs # VFS server, mount points
β β βββ blk_client.rs # Block device IPC client
β β βββ fat32/ # FAT32 filesystem
β βββ blkdev/ # Block device server
β β βββ Cargo.toml
β β βββ src/
β β βββ main.rs # IPC server loop
β β βββ virtio_mmio.rs # VirtIO MMIO registers
β β βββ virtqueue.rs # Virtqueue management
β β βββ blk.rs # VirtIO-blk protocol
β βββ netdev/ # Network device server
β β βββ Cargo.toml
β β βββ src/
β β βββ main.rs # IPC server loop
β β βββ virtio_mmio.rs # VirtIO MMIO registers
β β βββ virtqueue.rs # Virtqueue management
β β βββ net.rs # VirtIO-net protocol
β βββ fbdev/ # Framebuffer device server
β β βββ Cargo.toml
β β βββ src/
β β βββ main.rs # IPC server loop, backend selection
β β βββ virtio_gpu.rs # VirtIO-GPU driver (preferred)
β β βββ ramfb.rs # ramfb driver (fallback)
β β βββ fwcfg.rs # QEMU fw_cfg interface
β β βββ font.rs # 8x16 VGA bitmap font, text console
β βββ kbdev/ # Keyboard device server
β β βββ Cargo.toml
β β βββ src/
β β βββ main.rs # IPC server, keyboard polling
β β βββ input.rs # VirtIO-input driver
β βββ pipeserv/ # Pipe server (blocking pipes via deferred IPC)
β β βββ Cargo.toml
β β βββ src/main.rs
β βββ hello/ # Test program for spawn
β β βββ Cargo.toml
β β βββ src/main.rs
β βββ forktest/ # Phase 1 BusyBox support tests
β β βββ Cargo.toml
β β βββ src/main.rs
β βββ user.ld # Shared linker script
β βββ aarch64-kenix-user.json # Custom target spec
β βββ Cargo.toml # Workspace root
βββ docs/ # Documentation
β βββ syscalls.md # System call reference
β βββ ipc-protocols.md # IPC message formats
β βββ journal/ # Development notes
βββ scripts/ # Build scripts
β βββ create_disk.sh # FAT32 disk image creation
βββ Makefile
Kenix implements POSIX-style signals with user-space signal handlers:
- Signal sent -
kill(pid, sig)or automatic (e.g., SIGCHLD on child exit) - Signal queued - Added to target task's
pending_signalsbitmask - Delivery check - Before returning to user-space, kernel checks for deliverable signals
- Handler setup - If handler installed:
- Save current user context to signal stack
- Set up
siginfo_tanducontext_ton user stack - Redirect execution to user's signal handler
- Return address set to
sigreturntrampoline
- Handler runs - User-space handler executes
- sigreturn - Handler returns via
rt_sigreturnsyscall - Context restore - Kernel restores original context, resumes interrupted code
| Signal | Number | Default Action | Notes |
|---|---|---|---|
| SIGHUP | 1 | Terminate | |
| SIGINT | 2 | Terminate | Ctrl+C |
| SIGQUIT | 3 | Terminate | |
| SIGKILL | 9 | Terminate | Cannot be caught |
| SIGPIPE | 13 | Terminate | Broken pipe |
| SIGCHLD | 17 | Ignore | Child exited |
| SIGCONT | 18 | Continue | |
| SIGSTOP | 19 | Stop | Cannot be caught |
void handler(int sig) {
write(1, "Got signal!\n", 12);
}
struct sigaction sa = {
.sa_handler = handler,
.sa_flags = 0,
};
sigaction(SIGINT, &sa, NULL);- UEFI boot
- UART output
- Physical memory management (frame allocator)
- Paging (MMU, 2MB blocks)
- 4KB page support (L3 tables)
- Exception handler
- Preemptive scheduler (round-robin, timer-based)
- User-space tasks (EL0)
- ELF loader
- Syscall interface
- Pure Rust user-space (libkenix)
- Synchronous IPC (call/recv/reply)
- Deferred replies (reply_to for async patterns)
- Inline message passing (24 bytes)
- Shared memory IPC
- Asynchronous notifications (notify/wait_notify)
- Console server (UART + framebuffer forwarding)
- VFS server (ramfs + FAT32)
- Block device server (VirtIO-blk)
- Network device server (VirtIO-net)
- Framebuffer server (VirtIO-GPU or ramfb with text console)
- Keyboard server (VirtIO-input for GUI keyboard)
- Pipe server (blocking pipes with deferred replies)
- FAT32 filesystem
- Per-task fd table
- stdin/stdout/stderr
- read() syscall
- write() syscall
- close() syscall
- lseek() syscall
- pipe() syscall (blocking pipes via pipeserv)
- dup/dup2/dup3 syscalls
- spawn() syscall (create process from ELF in memory)
- execve() syscall (execute program from VFS path)
- getpid() syscall
- exit() syscall
- brk() syscall (heap management)
- getcwd/chdir syscalls (working directory)
- fork() syscall (copy-on-write not yet implemented, full copy)
- wait/waitpid syscalls
- Anonymous mmap/munmap with demand paging
- mprotect (stub)
- File-backed mmap (pre-faulted)
- Copy-on-write (COW)
- Swapping
- Signal state tracking (mask, pending, handlers)
- sigaction syscall (install signal handlers)
- sigprocmask syscall (block/unblock signals)
- kill syscall (send signal to process)
- SIGCHLD delivery on child exit
- Signal delivery to user-space handlers
- sigreturn syscall (return from signal handler)
- Default signal actions (terminate, ignore)
- SA_RESTART, SA_SIGINFO flags (partial)
- set_tid_address syscall
- getrandom syscall
- prlimit64 syscall
- writev/readv syscalls
- ioctl TIOCGWINSZ (terminal size)
- ppoll syscall (blocking stdin)
- getpgid/setpgid syscalls
- fstatat syscall
- SIMD alignment fault emulation (unmodified musl binaries work)
- clock_gettime (CLOCK_MONOTONIC, CLOCK_REALTIME)
- nanosleep
- timer_create/timer_settime
- VirtIO-blk driver (block device)
- VirtIO-net driver (network)
- VirtIO-GPU driver (framebuffer with 2D acceleration)
- VirtIO-input driver (keyboard)
- ramfb driver (framebuffer via fw_cfg, fallback)
- ARM GIC (Generic Interrupt Controller)
- ARM timer interrupts (preemption)
- VirtIO interrupt-driven I/O
- Raspberry Pi 4/5 support
- ARM Chromebook support
- Capability-based security
- Resource limits
- Watchdog / task monitoring
- GDB stub for kernel debugging
- Kernel symbols for crash dumps
- Performance tracing

