Moxnox v1.0
- Het ontwerp, zoals de keuze van systeemaanroepen (syscalls), is gemodelleerd naar die van Windows NT.
- Tegelijkertijd is het in staat om software uit te voeren die geschreven is voor Unix-achtige systemen, mits deze hiervoor zijn gecompileerd. Het wordt geleverd met een volledig GNU-basissysteem.
- Het systeem is volwassen genoeg om Moxnox op Moxnox zelf te bouwen.
- Het draait op het favoriete Linux-bestandssysteem van velen (btrfs).
Versie 1.0 bestaat uit ongeveer 130.000 regels C++ en draait op amd64 en aarch64. De btrfs-code werkt voor basisdoeleinden, maar is nog niet robuust bewezen. Gebruikers wordt geadviseerd om geen andere bestandssystemen te mounten dan tijdelijke (throwaway) bestandssystemen.
Uitvoeren
Om Moxnox te testen in QEMU, download dan moxnox-amd64-1.0.img.gz en moxnox-kernel-amd64-1.0.efi. Gebruik gunzip moxnox-amd64-1.0.img.gz om het image te decomprimeren.
Voor amd64:
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
Voor ARM zou het volgende moeten werken:
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
Let op: Verhoog het geheugen van 1024 MB als u zware taken uitvoert, zoals self-hosting.
Installeren
Gebruik eerst gparted of een vergelijkbaar programma om een nieuwe partitie aan te maken. 32 GB is ruim voldoende. In onderstaande voorbeelden wordt de partitie aangeduid als /dev/nvme0n1p99.
Zorg ervoor dat u een recente versie van btrfs-progs heeft, aangezien sommige standaardinstellingen van oudere versies niet worden ondersteund.
Stap 1: De root-schijf voorbereiden
# 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
Stap 2: De kernel kopiëren
# mount /boot/efi
# cd /boot/efi
# wget https://github.com/maharmstone/moxnox/releases/download/v1.0/moxnox-kernel-amd64-1.0.efi
Stap 3: De boot-entry installeren
# efibootmgr -c -d /dev/nvme0n1 -p 1 -L "Moxnox" -l '\moxnox-kernel-amd64-1.0.efi' -u 'root=/dev/nvme0n1p99'
Let op: efibootmgr wijzigt vaak de bootvolgorde daarna; dit is mogelijk niet gewenst. De namen van block-devices zijn grotendeels gelijk op Linux en Moxnox.
Het "EFI"-bestand is een polyglot-bestand dat ook voldoet aan het Linux-bootprotocol, waardoor het mogelijk ook werkt op non-EFI GRUB (niet getest).
Hardwareondersteuning
CPU
- amd64: Alles is gecompileerd voor x86-64-v3, wat vrijwel alles vanaf circa 2015 dekt. Moxnox gebruikt en activeert automatisch AVX512 indien gedetecteerd. Voor QEMU is het
q35machine-type vereist; het standaardpctype is te oud en mist PCI Express.microvmwerkt ook. - aarch64: Er wordt gebruikgemaakt van LSE atomics, wat ARMv8.1 vereist. Dit betekent dat het werkt op de Raspberry Pi 5, maar niet op oudere modellen. Moxnox ondersteunt alleen ACPI, geen Device Tree. Voor de Pi is daarom ook rpi5-uefi nodig. In QEMU werkt
virtensbsa-ref.
Apparaatondersteuning
- Block devices: NVMe, SATA, SDHCI (o.a. SD-kaarten), virtio-block, USB mass storage.
- Netwerkkaarten: virtio-net, RTL8168, RTL8125.
- Invoerapparaten: USB HID, PS/2 toetsenbord, PS/2 muis, virtio-input.
- Grafisch: virtio-gpu, GOP framebuffer, VBE, VGA tekstconsole (geef
text=80x25mee bij non-UEFI boots). - Seriële poorten: virtio-console, x86 seriële poort, PL011 ARM seriële poort.
- USB: XHCI.
Bouwen
De eenvoudigste manier om te bouwen is via de Docker-containers maharmstone/moxnox-ci-amd64 of maharmstone/moxnox-ci-aarch64, die de cross-compilers voor x86_64-pc-moxnox of aarch64-pc-moxnox bevatten.
In de container:
$ git clone https://github.com/maharmstone/moxnox
$ cd moxnox
CMake compileert de submodules die zijn uitgevinkt. Voor een minimaal systeem:
$ 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
Voor alle poorten (dit kan lang duren):
$ git submodule update --init --recursive
Compileren:
$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=amd64.cmake -GNinja ..
# Of voor ARM:
$ cmake -DCMAKE_TOOLCHAIN_FILE=clang-aarch64-native.cmake -GNinja ..
Belangrijk: Specificeer altijd Ninja, omdat C++ modules worden gebruikt. De standaard Unix Makefiles van CMake werken niet.
Afronden:
$ ninja
Let op: gcc, llvm en rust worden niet gecompileerd tenzij dit expliciet wordt gevraagd vanwege hun omvang. Hexyl en ripgrep moeten ook expliciet worden opgegeven vanwege hun afhankelijkheid van Rust.
Bouwen op Moxnox zelf: Volg bovenstaande stappen, maar zonder toolchain-bestand: cmake -GNinja .... Opmerking: gcc, rust, hexyl en ripgrep kunnen nog niet in Moxnox worden gecompileerd, maar de rest werkt (uiteindelijk). Dit vereist veel RAM en geduld. Indien CMake klaagt over rust-libc, zorg dan dat de Rust-submodules niet zijn uitgevinkt.
Licentie
- De kernel en first-party programma's vallen onder de GPL.
- De first-party DLL's vallen onder de LGPL.
- De inhoud van de
modulesdirectory is MIT. - Voor details over de poorten dient men de licenties van de respectievelijke submodules te raadplegen.
Poorten
Huidige poorten:
- bash
- binutils
- bison
- bzip2
- cairo
- cmake
- coreutils
- curl
- diffutils
- expat
- file
- findutils
- flex
- freetype
- gawk
- gcc (alleen amd64)
- git
- gmp
- gperf
- grep
- gzip
- harfbuzz
- hexyl
- jsoncpp
- less
- libarchive
- libiconv
- libpng
- librhash
- libuv
- llvm
- m4
- make
- mako
- markupsafe
- mesa
- mpc
- mpfr
- nano
- ncurses
- netcat
- ninja
- openssh
- openssl
- patch
- perl
- pixman
- python
- pyyaml
- readline
- ripgrep
- rust
- sed
- tar
- vim
- wget
- xz
- zlib
- zstd
Veelgestelde vragen (FAQs)
Wat ontbreekt er nog?
Veel, aangezien dit versie 1.0 is. In het bijzonder:
- Een GUI.
- Ondersteuning voor verschillende tijdzones.
- Ondersteuning voor verschillende toetsenbordindelingen.
- Locales en niet-UTF-8 tekensets.
- Elke vorm van beveiliging.
- Meerdere gebruikers en groepen.
Performance-gerelateerde punten:
- De userspace heap allocator kan sneller (dit is de bottleneck bij self-hosting).
- TCP is traag, omdat er geen MSS wordt onderhandeld en er wordt vastgehouden aan het standaard 64KB window.
- Er zou "early writeback" moeten plaatsvinden bij geheugendruk.
- Er moet een LRU-systeem komen om schone pagina's uit de page cache te verwijderen. Dit wordt verergerd door het feit dat de dentry-cache nooit wordt geschoond, waardoor inodes open blijven tot ze worden verwijderd.
- Er is behoefte aan meer poorten en hardwareondersteuning.
Hoe compatibel is het met NT?
De afspraak is dat de syscalls en low-level interfaces overeenkomen met die van NT, maar niet de daemons of de interne structuur van de kernel. Dit verschilt van ReactOS, dat een exacte recreatie van Windows nastreeft.
- Binaries zijn in PE-formaat (in plaats van ELF) en hebben een
.exeof.dllextensie. - C++ exceptions worden afgehandeld via SEH.
- POSIX-signalen worden afgehandeld via Asynchronous Procedure Calls (APC's).
- Alle niet-kernel-gerelateerde kernel-taken worden uitgevoerd in
ntdll.dll. - De
rcx, rdx, r8, r9calling convention komt overeen met die van Windows. - C-eigenaardigheden volgen Windows:
sizeof(long) == sizeof(int32t),sizeof(wchart) == sizeof(char16_t),sizeof(long double) == sizeof(double).
Ontbrekende NT-onderdelen zijn onder andere tokens, het Register en I/O completion ports.
Het virtuele bestandssysteem van NT (waarbij C:\Windows\System32 eigenlijk \Device\HarddiskVolume1\Windows\System32 is) is niet gereproduceerd. Paden zijn POSIX-achtig: slashes in plaats van backslashes, / als root en gemounte directories. In tegenstelling tot echt Windows, resolveert NtCreateFile de tekens . en .. om beter te werken met de dentry-cache.
Andere zaken die bewust niet zijn gekopieerd zijn de diverse transactievormen en het concept van "paged kernel memory".
Hoe compatibel is het met POSIX?
Er zijn 642 van de ongeveer 1.200 functies in POSIX 2024 geïmplementeerd. Dit is het overgrote deel van wat in de praktijk wordt gebruikt, waarbij gnulib eventuele tekortkomingen opvangt. In tegenstelling tot Windows is fork aanwezig. Er is gebruikgemaakt van musl voor wiskundige en cryptografische functies, mingw voor printf en andere zaken, en tre voor regexes.
De POSIX-functies zijn verdeeld over ucrtbase, iphlpapi en ws2_32 (zoals op Windows). Alles wat Windows niet implementeert, is ondergebracht in mnposix. Er is veel geleend van Linux: de dentry-cache, large folios, mapping van het volledige fysieke geheugen en evdev.
Tekortkomingen in POSIX:
AFUNIXis half voltooid.socketpairwerkt (inclusief SCMRIGHTS, wat ssh gebruikt), maar normale client-server code werkt niet.mkfifomaakt een inode aan, maar I/O wordt niet correct omgeleid naar een buffer.- APC's (signalen) worden alleen afgeleverd wanneer een thread terugkeert van een syscall. Een programma dat
while (true) { }uitvoert, is momenteel dus niet te killen.
Hoe start ik sshd?
Er is nog geen automatisering voor daemons, dus dit moet handmatig gebeuren.
- Genereer de host key:
# ssh-keygen -A
- Er zijn nog geen wachtwoorden; voeg daarom een
/root/.ssh/authorized_keysbestand toe om verbinding te kunnen maken. Controleer of/rooteigendom is van root, anders negeert sshd dit bestand. - Start sshd via het volledige pad:
# /bin/sshd.exe
Kan dit Windows-programma's uitvoeren?
Nee, tenminste nog niet. Er zijn bewust geen Win32 DLL's geïmplementeerd, op enkele functies in kernelbase na die door de mingw-runtime worden vereist. Een toekomstige verbetering zou zijn om deze volledig te verwijderen en de Win32 DLL-versies van Wine te porten. Onderdelen van Wine zoals wineserver en ntdll zijn niet nodig, aangezien deze al zelf zijn geïmplementeerd.
In hoeverre is dit "slordig" (gebruik van AI)?
Geen van de inhoudelijke code is geschreven door AI. AI is enkel gebruikt voor mechanische delen van het porten (bijv. autotools vertalen naar CMake, ioctl calls vervangen door tcgetwinsize, C-structs vertalen naar Rust) en voor het schrijven van sommige smoke tests (bijv. cairo-test, mesa-test).
Claude is vooral nuttig gebleken bij het reviewen van commits om geheugenlekken of deadlocks op te sporen voordat deze publiek werden.
Waarom dit project?
Voor de lol. Daarnaast is het schrijven van een eigen OS de enige manier om echt te leren hoe iets werkt.
De NT-kernel is bovendien zwaar onderschat en vrijwel onbekend bij hobbyisten. Het had functies die Linux pas jaren later implementeerde, zoals eventfd and pidfd. Het is jammer dat Windows wegstapt van volledige POSIX-compatibiliteit (zie WSL1 en Nano Server). Dit project is een visie op hoe Windows had kunnen zijn.
Groetjes,