Moxnox 1.0:运行于 Btrfs 之上的类 NT、兼容 POSIX 的操作系统

Hacker News Top 工具

摘要

Moxnox 1.0 是一个类似 NT、兼容 POSIX 的业余操作系统,运行于 btrfs 文件系统之上,由约 130,000 行 C++ 代码编写而成,支持 amd64 和 aarch64 架构,并且能够自举。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/10/28 01:51

maharmstone/moxnox

来源:https://github.com/maharmstone/moxnox

Moxnox v1.0

Moxnox 是一个类似 NT、兼容 POSIX 的业余操作系统,运行于 btrfs 之上,并且 能够自举。这意味着:

  • 它的设计(例如系统调用的选择)以 Windows NT 为蓝本……
  • ……但同时,它应该能够运行针对类 Unix 系统编写的软件, 前提是这些软件已为它重新编译,并且它附带 完整的 GNU 基础系统
  • 它已经足够成熟,可以在 Moxnox 上构建 Moxnox
  • 而且它运行在大家最喜欢的 Linux 文件系统上

1.0 版本约有 130,000 行 C++ 代码,可在 amd64 和 aarch64 上运行。

btrfs 代码可以满足基本用途,但尚未经过充分的实战检验。 请不要尝试挂载任何不能随意丢弃的文件系统。

截图

运行

要在 qemu 中测试 Moxnox,请下载 moxnox-amd64-1.0.img.gz (https://github.com/maharmstone/moxnox/releases/download/v1.0/moxnox-amd64-1.0.img.gz) 和 moxnox-kernel-amd64-1.0.efi (https://github.com/maharmstone/moxnox/releases/download/v1.0/moxnox-kernel-amd64-1.0.efi)。运行 gunzip moxnox-amd64-1.0.img.gz 解压镜像。

然后执行:

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

如果你打算尝试自举之类的高负载操作, 就需要将内存从 1024 MB 调高。

对于 ARM,类似下面的命令应该可以运行:

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

安装

首先,使用 gparted 或类似工具创建一个新分区。32 GB 应该 绰绰有余。下面我将它称为 /dev/nvme0n1p99——千万别弄错。

请确保使用较新版本的 btrfs-progs,因为我们不支持旧版本使用的 某些默认设置。

准备根分区: ``

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

``

复制内核: ``

mount /boot/efi

cd /boot/efi

wget https://github.com/maharmstone/moxnox/releases/download/v1.0/moxnox-kernel-amd64-1.0.efi

``

要安装启动项,可以执行类似下面的命令: ``

efibootmgr -c -d /dev/nvme0n1 -p 1 -L “Moxnox” -l ‘\moxnox-kernel-amd64-1.0.efi’ -u ‘root=/dev/nvme0n1p99’

``

efibootmgr 总喜欢在操作后更改启动顺序,这可能并不是 你想要的。块设备在 Linux 和 Moxnox 上的名称应该 基本相同。

这个“EFI”文件实际上是一个同时符合 Linux 启动协议的多格式文件, 所以它应该也能通过非 EFI 的 GRUB 启动。我没有测试过。 如何配置就留给读者自行探索了。

硬件支持

对于 amd64,所有内容都以 x86-64-v3 为目标编译,基本涵盖了 2015 年前后以来制造的所有设备。如果检测到 AVX512,Moxnox 会自动启用 并使用它。对于 qemu,你需要指定 q35 机器类型; 默认的 pc 机器太古老了,不支持 PCI Express。microvm 也可以使用。

对于 aarch64,我们使用 LSE 原子操作,它要求 ARMv8.1。这意味着 支持 Raspberry Pi 5,但不支持任何更早的型号。Moxnox 只支持 ACPI,不支持 设备树,所以在树莓派上还需要 https://github.com/worproject/rpi5-uefi。 遗憾的是,qemu 中没有 raspi5 机器类型,不过我已经成功使用 virt 运行,sbsa-ref 也可以。

设备支持:

  • 块设备:NVMe、SATA、SDHCI(即 SD 卡)、virtio-block、USB 大容量 存储设备
  • 网卡:virtio-net、RTL8168、RTL8125
  • 输入设备:USB HID、PS/2 键盘、PS/2 鼠标、virtio-input
  • 图形:virtio-gpu、GOP 帧缓冲、VBE、VGA 文本控制台(非 UEFI 启动时 传入 text=80x25)
  • 串口:virtio-console、x86 串口、PL011 ARM 串口
  • USB:XHCI

构建

最简单的构建方法是拉取 Docker 容器 maharmstone/moxnox-ci-amd64 或 maharmstone/moxnox-ci-aarch64,其中包含面向 x86_64-pc-moxnox 或 aarch64-pc-moxnox 的交叉编译器。

然后在容器中执行:

$ git clone https://github.com/maharmstone/moxnox $ cd moxnox

CMake 会编译所有已检出的子模块。对于最小 系统: $ 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

要构建所有移植软件,请执行以下命令,这可能需要一些时间: $ git submodule update --init --recursive

然后执行: $ mkdir build $ cd build $ cmake -DCMAKE_TOOLCHAIN_FILE=amd64.cmake -GNinja ..

或者

$ cmake -DCMAKE_TOOLCHAIN_FILE=clang-aarch64-native.cmake -GNinja ..

请务必指定 Ninja——因为我们使用了 C++ 模块,所以需要它。CMake 默认使用 Unix Makefiles,而这无法正常工作。

最后执行: $ ninja

由于体积较大,gcc、llvm 和 rust 默认不会编译,除非明确指定。 hexyl 和 ripgrep 也需要明确指定,因为它们 依赖 rust。

在 Moxnox 上构建的方法与上面相同,但不需要工具链文件:cmake -GNinja ..。 gcc、rust、hexyl 和 ripgrep 目前还不能在 Moxnox 中编译,但 其他所有软件都可以(只要等得足够久)。你可能需要大量内存,以及更多的 耐心。如果 CMake 报出有关 rust-libc 的错误,请确保你没有 检出 Rust 子模块。

许可证

内核和第一方程序采用 GPL 许可证。第一方 DLL 采用 LGPL 许可证。modules 目录中的内容采用 MIT 许可证。

有关各个移植软件的具体许可证,请参阅相应的子模块。

移植软件

目前已移植:

  • bash
  • binutils
  • bison
  • bzip2
  • cairo
  • cmake
  • coreutils
  • curl
  • diffutils
  • expat
  • file
  • findutils
  • flex
  • freetype
  • gawk
  • gcc(仅 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

常见问题

还缺少什么?

很多——但这毕竟是 1.0 版本。具体来说:

  • 图形用户界面
  • 对不同时区的支持
  • 对不同键盘布局的支持
  • 区域设置和非 UTF-8 字符集
  • 任何形式的安全机制
  • 多用户和用户组

至于性能等方面的问题:

  • 用户空间的堆分配器还有很大的提速空间(这是自举时的 瓶颈)
  • TCP 速度很慢,因为我们没有协商 MSS,并且一直使用默认的 64KB 窗口
  • 我们应该在内存紧张时提前回写
  • 应该有一个 LRU 系统,用于从页缓存中丢弃干净页……
  • ……而 dentry 缓存从不清理,导致 inode 在被删除之前一直保持打开状态,这又让问题更加严重

显然,还应该移植更多软件并支持更多硬件。

它与 NT 的兼容程度如何?

我们的约定是,系统调用和底层接口与 NT 保持一致, 但守护进程和内核本身的结构不必一致。这与 ReactOS 的目标不同,后者旨在精确复刻 Windows。

因此:

  • 二进制文件使用 PE 格式,而非 ELF,并带有 .exe 或 .dll 扩展名
  • C++ 异常通过 SEH 实现
  • POSIX 信号通过异步过程调用实现
  • 所有不在内核中、但类似内核的工作都在 ntdll.dll 中完成
  • rcx、rdx、r8、r9 调用约定与 Windows 一致
  • 它在 C 语言方面的古怪之处也与 Windows 一致:sizeof(long) == sizeof(int32_t)、 sizeof(wchar_t) == sizeof(char16_t)、sizeof(long double) == sizeof(double)。

NT 的内容非常多,但其中尚未实现、又比较有意思的部分 包括令牌、注册表和 I/O 完成端口。

NT 有一套复杂的系统,其中存在一个隐藏的虚拟文件系统 (除非使用 winobj,否则看不到),文件的真实路径以 其块设备名称为起点(所以 C:\Windows\System32 实际上可能是 \Device\HarddiskVolume1\Windows\System32)。 我没有复刻这些机制。路径采用 POSIX 风格:使用正斜杠而非 反斜杠,以 / 作为根文件系统,并通过目录进行挂载。与真正的 Windows 不同,NtCreateFile 会解析 . 和 ..,以便更好地配合 dentry 缓存。

我刻意没有照搬的其他内容包括各种形式的事务, 它们是特定时代的产物;还有可分页内核内存的概念, 它带来的问题比解决的问题更多。

它与 POSIX 的兼容程度如何?

我们已经实现了 POSIX 2024 中约 1,200 个函数里的 642 个。这涵盖了 实际使用中的绝大多数函数,gnulib 则弥补了其中的一些 不足。与 Windows 不同,这里有 fork。我使用了 musl 的数学 和加密函数、mingw 的 printf 和其他一些功能, 以及 tre 的正则表达式。

与 Windows 一样,POSIX 函数分布在 ucrtbase、iphlpapi 和 ws2_32 中, 而 Windows 未实现的功能则放在 mnposix 中。

我大量借鉴了 Linux 最出色的设计:dentry 缓存、大型 folio、 映射全部物理内存、evdev。

其他 POSIX 不足之处:

  • AF_UNIX 只完成了一半。socketpair 可以工作,包括 SCM_RIGHTS(ssh 会使用它),但常规的客户端—服务器代码无法工作
  • mkfifo 会创建一个 inode,但对它的 I/O 没有按预期重定向到 缓冲区
  • APC(即信号)只有在线程从系统调用返回时才会送达。 所以,目前运行 while (true) { } 的程序无法被终止。

如何启动 sshd?

目前还没有自动启动守护进程的机制,所以需要手动启动。

首先生成主机密钥: ``

ssh-keygen -A

``

目前还没有密码支持,因此需要添加一个 /root/.ssh/authorized_keys 文件才能连接。如果遇到问题,请再次检查 /root 是否 归 root 所有,否则 sshd 会忽略此文件。

然后使用完整路径启动 sshd: ``

/bin/sshd.exe

``

它能运行 Windows 程序吗?

不能。至少目前还不能。

我们有意不实现任何 Win32 DLL,除了 kernelbase 中 mingw 运行时需要的几个函数。未来的一项改进可以是 彻底移除这些函数,然后移植 Wine 的 Win32 DLL 实现。 Wine 的某些部分,比如 wineserver 和 ntdll,我们并不需要, 因为我们已经自行处理了它们的工作。

这项目有多潦草?

所有实质性代码都不是由 AI 编写的。

我用 AI 辅助完成移植中的机械性工作(例如将 autotools 转换为 CMake、将 ioctl 调用替换为 tcgetwinsize、将 C 结构体转换为 Rust),也用它编写了一些冒烟测试(例如 cairo-test、mesa-test)。

不过,Claude 真正出色的地方在于审查你自己的提交。你给它 一个哈希值,它就会在你出丑之前,指出你遗留下来的 低级内存泄漏或死锁。

为什么要做这个?

为了好玩。而且,真正弄懂某样东西如何工作的唯一方法, 就是亲手尝试写一个。

此外,NT 内核被低估得令人发指,而且几乎不为 业余爱好者所知。它拥有的一些功能,Linux 花了很多很多年才提出 自己的设计,例如 eventfd 和 pidfd。

Windows 总是在完全兼容 POSIX 这件事上退缩,实在令人遗憾。早期 它有一个半成品版本,后来又有了 WSL1,结果 还是放弃了。Nano Server 也是一个很酷的想法,却同样 被放弃了。所以,这就是我对心目中 Windows 应有模样的诠释。

相似文章

QSOE: 受QNX启发的双内核架构操作系统

Hacker News Top

QSOE项目v0.1发布,提供与QNX兼容的操作系统,包含两种微内核变体(自定义Skimmer内核和基于seL4的内核),共享用户空间,并支持SiFive Unmatched RISC-V硬件。