A hobby operating system kernel for x86-64 and arm64 (aarch64), written in C++20, Rust, and assembly.
Code is partially written by AI models (Claude, GPT) with human control over architecture decisions, testing, and code review.
Tested primarily in QEMU/KVM environments, including Google Cloud and Yandex Cloud VMs (MBR-based disk image, virtio devices), and on QEMU virt with HVF acceleration on Apple Silicon for the arm64 build. Real hardware support has not been tested.
- Two architectures — x86-64 (Multiboot2/GRUB, ISO or MBR disk boot) and arm64 (QEMU
virtboard, LinuxImageboot protocol); portable code goes through a HAL layer (src/cpp/hal/), arch backends live insrc/cpp/arch/ - SMP — up to 8 CPUs; AP bootstrap via INIT/SIPI on x86-64, PSCI
CPU_ONon arm64 - Preemptive multitasking — per-CPU task queues, round-robin scheduling, load-balanced task placement
- Virtual memory — 4-level paging (4 KB pages), high-half kernel at
0xFFFF800001000000, TLB shootdown across CPUs via IPI - Page allocator — fixed-size block allocator (1–128 contiguous pages), pool allocator (32 B – 2 KB),
new/deletesupport - ACPI — RSDP/RSDT/MADT parsing for LAPIC/IOAPIC discovery and IRQ→GSI routing
- Interrupts — IDT with exception handlers, IOAPIC routing (edge + level-triggered), LAPIC IPI, PIC (remapped then disabled)
- arm64 port — GICv3 interrupt controller with ITS (PCIe MSI delivered as LPIs,
its=onby default), EL1 exception vectors, ARM generic timer (per-CPU), PL011 UART, FDT (device tree) parsing, PCIe ECAM, virtio-mmio transport, broadcast TLBI, semantic memory barriers (dmb) throughout; NVMe over ITS-delivered MSI works end-to-end - Drivers — serial (COM1), VGA text mode, PIT (10 ms tick, SeqLock-protected counters), RTC (CMOS wall clock), PS/2 keyboard (8042), PCI bus scan, LAPIC, IOAPIC, virtio-blk, virtio-net, virtio-scsi, virtio-rng (legacy + modern virtio-pci transport), NVMe (Rust, MSI-X interrupt-driven)
- Block I/O — asynchronous, interrupt-driven block request queue with DMA slot pool,
BlockRequestsubmission withWaitGroupcompletion, direct DMA from caller buffers (page-aligned), virtqueue locking (RawSpinLock) for safe interrupt/task concurrency, early-boot polling fallback, SoftIrq-based retry for ring-full conditions, block device abstraction, MBR partition discovery - Networking — virtio-net driver with asynchronous interrupt-driven TX/RX, software frame queues (256-entry TX/RX) in
NetDevicebase class, reference-countedNetFramedescriptors for zero-copy DMA, TX slot pool with bitmask allocation, SoftIrq-based TX retry and RX processing, IP routing (subnet mask + gateway from DHCP, off-subnet traffic forwarded to gateway), ARP (cache, request, reply, dump), IPv4/UDP transmit, ICMP echo (ping reply + send, per-type statistics), DHCP client with lease renewal (sets IP, subnet mask, gateway, DNS server), DNS resolver with 32-entry cache (A-record queries, name compression, DHCP-provided server), TCP (connection state machine, 3-way handshake, sequence/ack tracking, retransmission timers, MSS negotiation, send/receive ring buffers, graceful close with FIN exchange, RST handling, ephemeral port allocation, granular locking:Mutexfor ports,RawSpinLockfor pool and per-connection state, SoftIrq-driven timer processing), HTTP client (URL parsing, DNS resolution, TCP connection, request/response, redirect following for 301/302/303/307/308 with loop limit,wgetshell command), UDP remote shell (execute kernel commands over the network), network device abstraction with per-protocol packet counters,MacAddress/IpAddressstructs (IPv6-ready tagged union) - Filesystem — VFS layer with mount points and path resolution, ramfs (in-memory), nanofs (on-disk filesystem with 4 KB blocks, superblock with UUID, inode/data bitmaps, CRC32 checksums for superblock/inodes/data, file and recursive directory deletion, persistent across remount)
- Entropy —
EntropySourceinterface,EntropySourceTableregistry, virtio-rng hardware random number generator - Power management — ACPI S5 shutdown, keyboard controller reset/reboot
- Interactive shell — trace output suppressed during shell session (dmesg only), restored on shutdown; commands:
ps,cpu,bt <pid>,dmesg [filter],uptime,date,memusage,pci,disks,diskread,diskwrite,irqstat,net,arp,icmpstat,tcpstat,udpsend,ping,nslookup,dnsflush,dhcp,wget,random,format,mount,umount,ls,cat,write,mkdir,touch,del,panic,version,cls,help,poweroff,reboot - Timekeeping — TSC calibration via PIT channel 2 (multi-round median), KVM paravirt clock (
kvmclock) for accurate VM time, RTC wall clock, layered clock source selection (kvmclock → calibrated TSC → PIT fallback),GetBootTime()/GetWallTimeSecs()API - Kernel infrastructure — spinlocks, mutexes, SeqLock (single-writer/multi-reader), atomics, wait groups, SoftIrq deferred processing, IPI tasks, timers, watchdog, stack traces with symbol resolution, dmesg ring buffer (512 KB, 2048 messages), panic handler with backtrace and CPU/task context, per-device interrupt statistics, AP startup diagnostics, virtual-to-physical address translation (4-level page table walk), byte-order helpers (
Htons/Htonl/Ntohs/Ntohl) - Optimized stdlib —
MemSet,MemCpy,MemCmp,StrLen,StrCmp,StrStrimplemented in x86-64 assembly usingrep stosq/rep movsq/repe cmpsb/repne scasb(portable C versions on arm64) - Rust support —
#![no_std]Rust crates linked into the kernel viastaticlib, FFI bridge (rust_ffi.cpp) exposing kernel services to Rust: spinlocks, mutexes, wait groups, timers, SoftIRQ, MSI-X interrupts, legacy interrupts, DMA allocation, MMIO mapping, PCI config space, block device and network device registration, CPU/IPI/task APIs. kcore library provides safe Rust wrappers around kernel primitives. NVMe driver written entirely in Rust — PCI BAR mapping, admin + I/O queue pairs, MSI-X interrupt-driven completion, WaitGroup-based synchronous I/O, multi-device support, proper RAII cleanup on shutdown - Boot tests — allocator, btree, ring buffer, stack trace, multitasking, contiguous page alloc (up to 128 pages), parsing helpers, block device table, memset, memcpy, memcmp, strlen, strcmp, strstr
The build is parameterized by ARCH (default x86_64, or aarch64); objects go to out/$(ARCH)/.
Native (requires clang, nasm, ld, grub-mkrescue, rustup with x86_64-unknown-none target):
makeVia Docker (works on macOS / Apple Silicon):
./scripts/build-iso-docker.shThis produces nos.iso and bin/kernel64.elf (for GDB symbols).
arm64 (requires ld.lld, llvm-nm, rustup with aarch64-unknown-none-softfloat target; on macOS build in Docker):
make nocheck ARCH=aarch64This produces kernel-arm64.elf and nos-arm64.img (Linux Image format, bootable with QEMU -kernel).
Build a bootable qcow2 disk image (MBR, 2 partitions):
./scripts/build-disk.shThis produces nos.qcow2 (1 GB, MBR, virtio-blk compatible, suitable for KVM-based public clouds including Google Cloud Compute Engine).
With KVM (Linux):
qemu-system-x86_64 -enable-kvm -smp 8 -cdrom nos.iso -serial file:nos.log \
-device isa-debug-exit,iobase=0xf4,iosize=0x04Without KVM (macOS with TCG):
qemu-system-x86_64 -smp 2 -cdrom nos.iso -serial file:nos.log -s -vga stdBoot from disk image (with virtio-blk):
./scripts/qemu-disk.sharm64 on QEMU virt (HVF-accelerated on Apple Silicon, NOS_TCG=1 forces TCG; virtio-mmio blk/net/rng attached, serial goes to nos-arm64.log, UDP shell forwarded on :9000):
./scripts/qemu-arm64.sh
./scripts/smoke-arm64.sh # boot smoke test (SMOKE_HVF=1 for HVF)
python3 scripts/udpsh.py 127.0.0.1 # remote shell over UDPDeploy to Google Cloud Compute Engine (select Skip OS adaptation when importing the image — the kernel already has the necessary drivers and no guest agent):
# Upload disk image to a GCS bucket
gcloud storage cp nos.qcow2 gs://YOUR_BUCKET/nos.qcow2
# Create a Compute Engine image from the disk (skip OS adaptation)
gcloud compute images create nos-image \
--source-uri=gs://YOUR_BUCKET/nos.qcow2
# Launch a VM (serial console recommended)
gcloud compute instances create nos-vm \
--image=nos-image \
--machine-type=e2-small \
--metadata=serial-port-enable=true
# Connect via serial console
gcloud compute connect-to-serial-port nos-vmStart QEMU with -s (GDB server on port 1234), then:
gdb -ex "symbol-file bin/kernel64.elf" \
-ex "set architecture i386:x86-64" \
-ex "target remote :1234"arm64 (start ./scripts/qemu-arm64.sh -s, needs gdb-multiarch):
./scripts/gdb-arm64.shPass via GRUB command line on x86-64 (edit build/grub.cfg) or QEMU -append on arm64:
smp=off— disable SMP, run on BSP onlyconsole=serial— direct shell output to serial port onlyconsole=vga— direct shell output to VGA onlydhcp=auto— start DHCP oneth0automatically at bootdhcp=off— disable DHCP entirely (even via shell command)dhcp=on— enable DHCP only via shell command (default)dns=on— enable DNS resolver (uses DHCP-provided DNS server; requiresdhcp=auto)udpshell=PORT— start UDP remote shell on the given port (e.g.udpshell=9000)its=off— arm64 only: disable the GICv3 ITS and degrade PCIe MSI gracefully (defaultits=on; virtio-mmio devices don't need it)
When udpshell=PORT is set, the kernel listens for commands on that UDP port.
A lightweight protocol header (16 bytes: magic, sequence number, chunk index, flags, payload length) frames every packet, enabling the client to validate replies, reassemble multi-chunk responses in order, and detect the end of a response without relying on timeouts.
Connect with the included Python client:
python3 scripts/udpsh.py <vm-ip> [port] [timeout]- Default port is
9000, default timeout is30seconds (long enough for blocking commands likeping). - On protocol errors or timeouts, the client reconnects automatically and resets state.
- All shell commands work over the UDP session (including blocking ones like
ping). - Warning: the UDP shell has no authentication — anyone who can reach the port has full kernel shell access. Use only for testing or behind a firewall.
| Command | Description |
|---|---|
cls |
Clear screen |
cpu |
Dump CPU state |
dmesg [filter] |
Dump kernel log (optional substring filter) |
uptime |
Show uptime |
date |
Show wall clock date and time (RTC + boot time) |
ps |
Show tasks |
bt <pid> |
Dump stack trace of a task (uses IPI for remote CPUs) |
watchdog |
Show watchdog stats |
memusage |
Show memory usage |
pci |
Show PCI devices |
disks |
List block devices |
diskread <disk> <sector> |
Read and hex-dump a sector |
diskwrite <disk> <sector> <hex> |
Write hex data to a sector |
irqstat |
Show per-device interrupt counters |
help |
List commands |
net |
List network devices and per-protocol stats |
arp |
Show ARP table |
icmpstat |
Show ICMP statistics |
tcpstat |
Show TCP connections and statistics |
wget <url> |
Fetch a URL via HTTP GET (follows redirects) |
udpsend <ip> <port> <msg> |
Send a UDP packet |
ping <ip|hostname> |
Send 5 ICMP echo requests with RTT (resolves hostnames via DNS) |
nslookup <hostname> |
Resolve hostname to IP via DNS |
dnsflush |
Flush DNS cache |
dhcp [dev] |
Obtain IP address via DHCP |
random [len] |
Get random bytes as hex string |
format nanofs <disk> |
Format disk with nanofs |
mount ramfs <path> |
Mount a ramfs at path |
mount nanofs <disk> <path> |
Mount nanofs from disk at path |
umount <path> |
Unmount filesystem |
mounts |
List mount points |
ls <path> |
List directory contents |
cat <path> |
Show file contents |
write <path> <text> |
Write text to file (creates if needed) |
mkdir <path> |
Create directory |
touch <path> |
Create empty file |
del <path> |
Remove file or directory |
panic [type] |
Trigger kernel panic (direct, pagefault, divzero, ud) |
version |
Show kernel version |
poweroff / shutdown |
Power off (ACPI S5) |
reboot |
Reset system (keyboard controller) |
src/cpp/
hal/ Portable HAL contracts: cpu, barriers, mmu/pte, irqchip, console, power, context, irq stubs
arch/
x86_64/ Multiboot2 entry + AP trampoline (NASM), CPU primitives (asm.asm), IDT/GDT, exceptions, TSC/kvmclock, LAPIC/IOAPIC/PIC, PTE encoding, GRUB info parsing, HAL backends
arm64/ Linux-Image boot + PSCI SMP (boot.S), EL1 vectors, GICv3 + ITS (LPIs for PCIe MSI), generic timer, PL011, FDT parser, PCIe ECAM, PTE encoding, HAL backends
kernel/ Core: scheduling, tasks, interrupt dispatch, SoftIrq, shell, timers, timekeeping, locks, panic, Rust FFI bridge, symbol table
drivers/ Hardware: serial, VGA, PIT, HPET, RTC, 8042, PCI, MSI-X, ACPI, virtio blk/net/scsi/rng (virtio-pci on x86-64, virtio-mmio on arm64)
block/ Block I/O: device abstraction, async request queue, MBR partition discovery
net/ Networking: device abstraction, protocol headers, ARP, ICMP, DHCP, DNS, TCP, HTTP client, UDP shell
fs/ Filesystem: VFS, ramfs, nanofs, block I/O helpers
mm/ Memory: page tables (4-level walk, VirtToPhys), page allocator, pool allocator
lib/ Utilities: list, vector, btree, ring buffer, bitmap, CRC32 checksum, stdlib
include/ Shared headers
src/rust/
ffi/ Raw extern "C" FFI declarations for kernel services
kcore/ Safe Rust wrappers: sync, DMA, MMIO, MSI-X, interrupts, timers, tasks, PCI, block/net device
drivers/
nvme/ NVMe block device driver (PCI, MSI-X, admin/IO queues)
r8168/ Realtek r8168 network device driver
hello/ Rust self-test module
kernel/ Rust entry points (rust_main, rust_fini), global allocator
build/ Linker script, GRUB configs
scripts/ Build, run, debug, and GDB helpers