← 返回信息流
AI 资讯Hacker News·1 天前

在自制操作系统上通过 Wine 运行 Windows 游戏

原标题:Running Windows Games on a Hobby OS with Wine

速览

本文探讨了在自制或业余开发的操作系统上运行 Windows 应用程序的技术实践。通过集成 Wine 兼容层,开发者能够绕过原生 API 限制,实现 Windows 游戏的跨平台运行。这一尝试不仅展示了 Wine 在非常规环境下的兼容性潜力,也为操作系统开发提供了宝贵的互操作性参考。

AI 深度解读

在业余操作系统 Astral 上通过 Wine 运行 Windows 游戏

背景

几个月前,作者在 Hacker News 上分享过关于 Astral 的进展。Astral 是一个作者多年来一直在开发的业余操作系统(Hobby OS),当时已经成功在上面运行了 Minecraft。此后,社区其他开发者也实现了现代版本的 Minecraft 以及 Factorio(使用兼容 glibc 的 libc)在 Astral 上的运行。

然而,这些游戏之所以能相对容易地在新操作系统上运行,是因为它们的制作或打包方式本身就对跨平台兼容性做了优化。大多数游戏并非如此,许多游戏是闭源的且专为 Windows 编译。因此,对于这类游戏,Wine(一个允许在类 Unix 系统上运行 Windows 应用程序的兼容层)成为了必不可少的工具。

作者最喜欢的游戏之一 Cogmind 就属于这一类。它是一个仅支持 32 位 Windows 的 Roguelike 游戏。为了让它在 Astral 上运行,作者决定完善现有的 Wine 移植版本。值得注意的是,当时的 Wine 移植版本极不完整,甚至连 notepad.exe(记事本)都无法正常工作。此外,由于 Astral 是一个仅支持 64 位的操作系统,运行 32 位代码还需要额外的基础设施支持。

核心内容

基础 Wine 功能实现

让 Wine 跑起来的第一步是下载 MinGW 并在 Wine 构建中启用它,因为编译 PE(Portable Executable)DLL 需要用到 MinGW。启用 MinGW 后,notepad.exe 可以正常工作,且选择“另存为”时不再崩溃。

编译 libEGL.so 与图形支持

尽管 Astral 已经支持 OpenGL,但 Wine 明确需要 EGL 才能正常工作,而 Astral 移植的 Mesa 版本并未提供 EGL。EGL 的作用是将 OpenGL 等渲染 API 连接到窗口系统,这是 Wine 正确初始化图形所必需的。

起初,这看起来只是一个简单的修复:在 Mesa 中启用 EGL 即可。然而,Mesa 并不支持在 xlib 后端上使用 EGL,这迫使作者切换到 DRI(Direct Rendering Infrastructure,直接渲染基础设施)后端。

DRI 允许应用程序更直接地与 GPU 通信,而不是通过 X 服务器。这导致作者陷入了一系列复杂的调试工作中,不得不修补 Mesa,使其能够在没有 /dev/dri 设备的情况下启动 X.org 服务器。最终,作者成功让一款真正的游戏 Deltarune 启动了起来。

WoW64 与 32 位 Windows 程序支持

由于 Cogmind 是 32 位程序,而 Astral 是 64 位系统,需要更多的基础设施支持。这一目标通过 Wine 的 WoW64(Windows on Windows 64)模式实现。WoW64 不需要任何 32 位 Unix 库,它的工作原理是在 64 位进程中运行 32 位 Windows 二进制文件,并在必要时在 32 位和 64 位系统调用及数据结构之间进行转换,从而避免了对完整 32 位用户空间的需求。

实现 WoW64 支持主要涉及在内核中实现 LDT(Local Descriptor Table,局部描述符表)支持。x86-64 架构允许在长模式(long mode)下使用 32 位段描述符来运行 32 位代码。这些描述符定义了内存的访问方式,对于代码段而言,还定义了处理器执行指令的方式。LDT 是定义这些段描述符的机制之一,允许按进程进行配置。此外,还需要在 Wine 的信号和系统调用处理代码中添加一些精细的粘合代码。

解决 Cogmind 的分数上传故障

在 Astral 移植版中实现了 WoW64 支持并修复了内核中的几个其他 bug 后,Cogmind 终于能够运行!游戏可玩,除了游戏新闻和分数表上传功能无法使用外,没有其他明显问题。

分数上传失败的表现为:与 Cogmind 服务器建立的 TCP 连接被打开后立即关闭,且没有传输任何数据。起初,作者怀疑是网络栈的问题,但事实并非如此。

引起作者怀疑的线索是,在 WoW64 模式下,Wine 的调试日志函数 __wine_dbg_write 完全无法工作。经过深入挖掘 Wine 的代码,作者最终发现自己在 __wine_unix_call_dispatcher 函数中忘记保存一个寄存器。这破坏了 PE(Windows 可执行文件格式)到 Unix 的转换过程,导致了未定义行为(UB)。修复这一问题后,分数表上传功能恢复正常。

其他应用程序测试与未来展望

作者还尝试在 Wine 下运行其他应用程序,并总结了以下思考:

移植 Wine 是一个有趣的挑战,它证明了业余操作系统可以运行比最初设想多得多的游戏,这是朝着业余操作系统成为可行的日常驱动程序迈出的重要一步。尽管目前仍存在一些粗糙之处、性能问题和奇怪的崩溃,但核心功能已经工作。

这一过程也让作者深入了解了 Wine 的内部工作机制,特别是在修复 PE 到 Unix 转换过程中学到的知识。

作者目前的一个大目标是让 Steam 在 Astral 上运行,这意味着 Chromium 也将随之工作。对于 Astral 本身,作者计划在未来专注于优化、新驱动程序和 bug 修复。内核层面仍有巨大的改进空间。

关键要点

  • 跨平台兼容性挑战:虽然像 Minecraft 和 Factorio 这样的游戏因打包方式易于移植,但大多数闭源 Windows 游戏需要 Wine 才能在非 Windows 系统上运行。
  • 图形栈的关键作用:Wine 依赖 EGL 连接渲染 API 和窗口系统。由于 Mesa 在 xlib 后端不支持 EGL,作者不得不切换到 DRI 后端,并修补 Mesa 以在无 /dev/dri 环境下启动 X.org 服务器。
  • WoW64 的实现机制:在 64 位操作系统上运行 32 位程序无需完整的 32 位用户空间,而是通过 WoW64 模式,在 64 位进程中模拟 32 位环境。这需要内核支持 LDT(局部描述符表)以处理 x86-64 架构下的 32 位段描述符。
  • 底层调试的重要性:分数上传失败的根本原因是一个被遗忘的寄存器保存操作,这导致了 PE 到 Unix 转换过程中的未定义行为。这凸显了深入理解系统调用和信号处理机制的重要性。
  • 业余操作系统的可行性:成功运行 Cogmind 和 Deltarune 证明了业余操作系统(Hobby OS)具备运行复杂 Windows 游戏的能力,向成为日常主力操作系统迈出了重要一步。
  • 未来路线图:作者计划进一步移植 Steam 和 Chromium,并持续优化 Astral 的内核性能、驱动程序和稳定性。

意义与影响

这项工作在技术社区具有多重意义。首先,它展示了 Wine 移植的复杂性和深度,不仅仅是简单的二进制兼容,还涉及到底层图形栈(Mesa/EGL/DRI)、系统架构(WoW64/LDT)以及内核细节的紧密配合。

其次,对于 Astral 这样的业余操作系统而言,这是一个里程碑式的成就。它打破了“业余操作系统只能运行简单程序”的刻板印象,证明了通过努力, hobby OS 可以具备运行主流商业游戏和复杂应用程序的能力。这为 hobby OS 从“技术演示”走向“日常可用”提供了有力的实证支持。

最后,这一过程积累的关于 Wine 内部机制、PE 转换以及 x86-64 架构下 32/64 位混合执行的知识,对于其他操作系统开发者或系统程序员来说,也是极具价值的参考案例。随着 Steam 和 Chromium 等关键应用的逐步支持,Astral 的生态完整性将得到显著提升。

查看原文 →astral-os.org