Moxnox is an NT-like, POSIX-compatible hobby OS which runs on btrfs and is capable of self-hosting. That means:
Version 1.0 is around 130,000 lines of C++, and runs on amd64 and aarch64.
The btrfs code works for basic purposes, but has not been battle-hardened. Please don't try to mount anything but throwaway filesystems.
To test Moxnox in qemu, download moxnox-amd64-1.0.img.gz and moxnox-kernel-amd64-1.0.efi. Run gunzip moxnox-amd64-1.0.img.gz to decompress the image.
Then:
qemu-system-x86_64 -M q35 -enable-kvm -cpu host -m 1024 \
-smp cores=4,threads=1 \
-kernel moxnox-kernel-amd64-1.0.efi \
-append "root=/dev/sda" \
-device ich9-ahci,id=ahci -drive id=disk,file=moxnox-amd64-1.0.img,if=none \
-device ide-hd,drive=disk,bus=ahci.0 \
-nic user,model=virtio-net-pci \
-device qemu-xhci \
-device usb-kbd,id=kbd \
-device usb-tablet,id=tablet \
-serial stdio
You will need to increase the memory from 1024 MB if you are trying anything strenuous, like self-hosting.
For ARM, something like the below should work:
qemu-system-aarch64 -M virt -cpu cortex-a76 -m 1024 \
-smp cores=4,threads=1 \
-kernel moxnox-kernel-aarch64-1.0.efi \
-append "root=/dev/sda" \
-device ich9-ahci,id=ahci -drive id=disk,file=moxnox-aarch64-1.0.img,if=none \
-device ide-hd,drive=disk,bus=ahci.0 \
-nic user,model=virtio-net-pci \
-drive if=pflash,unit=0,file=/usr/share/qemu/edk2-aarch64-code.fd,readonly=on \
-device qemu-xhci \
-device usb-kbd,id=kbd \
-device usb-tablet,id=tablet \
-serial stdio
First, use gparted or similar to create a new partition. 32 GB should be plenty. I'm calling it /dev/nvme0n1p99 below - don't get this wrong.
Make sure you have a recent versions of btrfs-progs, as we don't support some of the default settings used by the older versions.
Prepare the root drive:
# mkfs.btrfs /dev/nvme0n1p99
# mkdir /mnt/moxnox
# mount /dev/nvme0n1p99 /mnt/moxnox
# cd /mnt/moxnox
# wget https://github.com/maharmstone/moxnox/releases/download/v1.0/moxnox-amd64-1.0.tar.gz
# tar -xvzf moxnox-amd64-1.0.tar.gz
# rm moxnox-amd64-1.0.tar.gz
# cd
# umount /mnt/moxnox
Copy the kernel:
# mount /boot/efi
# cd /boot/efi
# wget https://github.com/maharmstone/moxnox/releases/download/v1.0/moxnox-kernel-amd64-1.0.efi
To install the boot entry, do something like:
# efibootmgr -c -d /dev/nvme0n1 -p 1 -L "Moxnox" -l '\moxnox-kernel-amd64-1.0.efi' -u 'root=/dev/nvme0n1p99'
efibootmgr likes to change the boot order afterwards, this probably is not what you want. The names of block devices should be more or less the same on Linux and Moxnox.
The "EFI" file is actually a polyglot file that also conforms to the Linux boot protocol, so it should also work on non-EFI GRUB. I have not tested this. How to set this up is left as an exercise for the reader.
For amd64, everything is compiled for x86-64-v3, which covers more or less anything manufactured since 2015 or so. Moxnox automatically uses and enables AVX512 if it detects it. For qemu, you need to specify the q35 machine type; the default pc machine is ancient, and doesn't have PCI Express. microvm works too.
For aarch64, we're using LSE atomics, which require ARMv8.1. That means the Raspberry Pi 5, but not any earlier models. Moxnox only supports ACPI, not Device Tree, so for the Pi you will also need https://github.com/worproject/rpi5-uefi. Unfortunately there is no raspi5 machine type in qemu, but I have had success with virt, and sbsa-ref works too.
Device support:
text=80x25 on non-UEFI boots)The easiest way to build is to pull the Docker containers maharmstone/moxnox-ci-amd64 or maharmstone/moxnox-ci-aarch64, which contain the cross-compilers for x86_64-pc-moxnox or aarch64-pc-moxnox.
Then in the container:
$ git clone https://github.com/maharmstone/moxnox
$ cd moxnox
CMake will compile whichever of the submodules are checked out. For a minimal system:
$ git submodule update --init --depth 1 ports/acpica/repo ports/freetype/repo ports/gnu-efi/repo ports/harfbuzz/repo ports/libpng/repo ports/mingw-w64/repo ports/zlib/repo ports/musl/repo ports/tre/repo
For all of the ports, which might take a while:
$ git submodule update --init --recursive
Then:
$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=amd64.cmake -GNinja ..
or
$ cmake -DCMAKE_TOOLCHAIN_FILE=clang-aarch64-native.cmake -GNinja ..
Make sure you specify Ninja - we need this as we're using C++ modules. CMake defaults to Unix Makefiles, which don't work.
Finally:
$ ninja
gcc, llvm, and rust are not compiled unless explicitly requested due to their size. hexyl and ripgrep also need to be specified explicitly due to their dependency on rust.
To build on Moxnox, as above, but you don't need a toolchain file: cmake -GNinja ... gcc, rust, hexyl, and ripgrep can't yet be compiled in Moxnox, but everything else works (eventually). You may need a lot of RAM and even more patience. If CMake complains about rust-libc, make sure that you don't have the Rust submodules checked out.
The kernel and first-party programs are licensed under the GPL. The first-party DLLs are licensed under the LGPL. The contents of the modules directory are MIT.
See the ports submodules for details of their particular licences.
Current ports:
Loads - but this is version 1.0. In particular:
For performance issues and similar:
And obviously there should be more ports and hardware support.
The contract is that the syscalls and low-level interfaces match those of NT, but not the daemons or how the kernel itself is structured. This is in contrast to what ReactOS aims to do, which is an exact recreation of Windows.
So:
.exe or .dll extensionntdll.dllsizeof(long) == sizeof(int32_t), sizeof(wchar_t) == sizeof(char16_t), sizeof(long double) == sizeof(double).There's an awful lot of stuff in NT, but the interesting stuff that's missing is tokens, the Registry, and I/O completion ports.
NT has a complex system where there's a virtual filesystem but it's hidden (unless you use winobj), with the true path of a file hanging off the name of its block device (so C:\Windows\System32 might actually be \Device\HarddiskVolume1\Windows\System32). I've not replicated any of that. Paths are POSIX-like: slashes rather than backslashes, / as the root filesystem, and mounted directories. Unlike real Windows, NtCreateFile resolves . and .., to work better with the dentry cache.
Other things I've deliberately not copied are the various forms of transactions, which were a product of their time, and the idea of paged kernel memory, which causes more problems than it solves.
We have implemented 642 of the ~1,200 functions in POSIX 2024. This is the vast majority of what's used in practice, with gnulib papering over some of the cracks. Unlike Windows, fork is there. I've used musl for its mathematical and cryptographic functions, and mingw for printf and some other things, and tre for its regexes.
The POSIX functions are split over ucrtbase, iphlpapi, and ws2_32, as on Windows, with anything that Windows doesn't implement put in mnposix.
I've borrowed liberally from Linux's best ideas: the dentry cache, large folios, mapping the whole of physical memory, evdev.
Other POSIX shortcomings:
socketpair works, including for SCM_RIGHTS (ssh uses this), but the normal client-server code doesn't workmkfifo creates an inode, but I/O to it does not get redirected to a buffer as it ought to dowhile (true) { } is currently unkillable.There's nothing that automatically starts daemons yet, so manually.
First generate the host key:
# ssh-keygen -A
There's no passwords yet, so you will need to add a /root/.ssh/authorized_keys file so that you can connect. If you have trouble, double-check that /root is owned by root, as sshd will ignore this file otherwise.
Then start sshd using its full path:
# /bin/sshd.exe
No. Or at least, not yet.
We deliberately do not implement any Win32 DLLs, bar a few functions in kernelbase that the mingw runtime wants. A future improvement would be to strip these out entirely, then port across Wine's versions of the Win32 DLLs. Some parts of Wine, like wineserver and ntdll, we would not need as we are already taking care of it ourselves.
None of the substantive code was written by AI.
I used AI to help with the mechanical parts of porting (e.g. translating autotools to CMake, replacing ioctl calls with tcgetwinsize, translating the C structs into Rust), as well as to write some of the smoke tests (e.g. cairo-test, mesa-test).
Where Claude really shines though is in reviewing your own commits. You give it a hash, and it tells you about the silly memory leak or deadlock that you left in, before you can make a fool of yourself.
For funsies. Plus the only way of really learning how something works is to have a go at writing it yourself.
Also, the NT kernel is criminally underrated, and pretty much unknown to hobbyists. It had features that Linux took years and years to come up with its own design for, such as eventfd and pidfd.
It's a shame that Windows keeps shying away from full POSIX compatibility. They had a half-complete version in the early days, then more recently had WSL1, only to then abandon it. And Nano Server was another cool idea, only again to be itself abandoned. So this is my take on what I wish Windows had been like.