My dual-arch AI OS boots on QEMU, VirtualBox and real UEFI hardware. Three bugs that cost me the most.
I've been writing an OS from scratch in Rust for the last few months. x86_64 and
aarch64 from one codebase, no_std, no libc, no POSIX layer. Boots on QEMU,
VirtualBox, real UEFI hardware, and on a Mac mini M2 over m1n1.
What's in it so far: preemptive scheduler, MMU and frame allocator, capabilities
and IPC, SMP on both arches, virtio/NVMe/AHCI block, GPT/MBR with FAT, ext4 and
exFAT, xHCI + HID (keyboard and mouse, driven off the report descriptor), a
TCP/IP stack with TLS, a framebuffer compositor with split panes and tabs, and
in-kernel PNG/JPEG/MP3/AAC/H.264/H.265/VP9 decoders.
Three bugs that cost the most, in case they save anyone else the time.
- aarch64 preemption worked exactly once per boot. The x86 context switch saved
RFLAGS. The aarch64 one saved x19-x30 and d8-d15 and left DAIF alone, as if it
were a global CPU property. IRQs are masked on exception entry, so the first
preemptive switch out of the timer handler handed the incoming task a masked DAIF
that nothing ever cleared, and from then on the machine ran with interrupts off.
The interactive shell hid it completely because it yields constantly. I only
found it the day I got the unit suite running on aarch64 — it had been x86-only,
so about 2,400 tests gated every x86 change and nothing gated ARM beyond "it
compiles."
- X_DSDT is at FADT offset 140, not 148. I had 148, which is where the PM1a
event block's GAS starts, so I was reading space|width|offset|access|address_lo32
reinterpreted as a u64 — a big plausible number that went straight past my
sanity check. The DSDT was therefore unfindable on every machine with a modern
FADT, so the whole AML layer silently did nothing: no _S5 poweroff, no battery,
no I2C touchpad. No error anywhere, because "no DSDT" is a legitimate state.
- The same image booted under HVF and died under TCG. QEMU virt puts its 64-bit
PCIe window at exactly 512 GiB, and my identity map was a 39-bit VA — one L1 of
512 1 GiB blocks — so it couldn't describe 0x8000000000 at all, and the mapping
function just returned without saying anything. A driver then wrote to the
unmapped address it got back. TCG gives the guest enough physical space for
firmware to put a BAR up there and HVF doesn't, so it genuinely did work on my
machine.
It runs an AI agent as the unit of execution instead of loading binaries, which
is why I started it, but the OS underneath is where the time went.
Not stable, research OS, run it in a VM. Apache-2.0, prebuilt images for both
arches.